一、NSOperation 抽象类

  • NSOperation 是一个"抽象类",不能直接使用。抽象类的用处是定义子类共有的属性和方法。
  • NSOperation 是基于 GCD 做的面向对象的封装。
  • 相比较 GCD 使用更加简单,并且提供了一些用 GCD 不是很好实现的功能。
  • 苹果公司推荐使用的并发技术。
  • 两个子类:
    • NSInvocationOperation (调用)
    • NSBlockOperation (块)

相比NSInvocationOperation推荐使用NSBlockOperation,代码简单,同时由于闭包性使它没有传参问题。

  • NSOperationQueue 队列

已经学习过的抽象类

  • UIGestureRecognizer
  • CAAnimation
  • CAPropertyAnimation

二、 NSOperation 和 GCD 的核心概念

  • GCD的核心概念:将 任务(block) 添加到队列,并且指定执行任务的函数。
  • NSOperation 的核心概念:将 操作 添加到 队列。

三、NSOperation 和 GCD的区别:

GCD

  • 将任务(block)添加到队列(串行/并发/主队列),并且指定任务执行的函数(同步/异步)
  • GCD是底层的C语言构成的API
  • iOS 4.0 推出的,针对多核处理器的并发技术
  • 在队列中执行的是由 block 构成的任务,这是一个轻量级的数据结构
  • 要停止已经加入 queue 的 block 需要写复杂的代码
  • 需要通过 Barrier 或者同步任务设置任务之间的依赖关系
  • 只能设置队列的优先级
  • 高级功能:
    • 一次性 once
    • 延迟操作 after
    • 调度组

NSOperation

  • 核心概念:把操作(异步)添加到队列(全局的并发队列)。
  • OC 框架,更加面向对象,是对 GCD 的封装。
  • iOS 2.0 推出的,苹果推出 GCD 之后,对 NSOperation 的底层全部重写。
  • Operation作为一个对象,为我们提供了更多的选择。
  • 可以跨队列设置操作的依赖关系
  • 可以设置队列中每一个操作的优先级
  • 高级功能:
    • 最大操作并发数(GCD不好做)
    • 继续/暂停/全部取消
    • 跨队列设置操作的依赖关系

四、代码实践

 //
// ViewController.m
// NSOperationTest
//
// Created by mayl on 2018/1/5.
// Copyright © 2018年. All rights reserved.
// #import "ViewController.h" @interface ViewController ()
@property(nonatomic, strong) NSOperationQueue *gOpQueue;
@end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
[self setUpUI]; // [self aysncCon];
[self maxConCount];
// [self oftenUse];
// [self setUpDependence];
// [self waitUntilFinished];
} - (void)setUpUI{ //暂停,继续按钮
UIButton *lBtn4Pause = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:lBtn4Pause]; lBtn4Pause.frame = CGRectMake(, , , );
[lBtn4Pause setTitle:@"挂起" forState:UIControlStateNormal];
lBtn4Pause.titleLabel.numberOfLines = ;
[lBtn4Pause setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[lBtn4Pause addTarget:self action:@selector(pauseBtnDidClick:) forControlEvents:UIControlEventTouchUpInside]; //取消所有任务按钮
UIButton *lBtn4CancelAll = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:lBtn4CancelAll]; lBtn4CancelAll.frame = CGRectMake(, , , );
[lBtn4CancelAll setTitle:@"cancel all" forState:UIControlStateNormal];
[lBtn4CancelAll setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[lBtn4CancelAll addTarget:self action:@selector(cancelAllBtnDidClick:) forControlEvents:UIControlEventTouchUpInside];
} #pragma mark - action /**
队列挂起,当前"没有完成的操作",是包含在队列的操作数中的。
队列挂起,不会影响已经执行操作的执行状态。
队列一旦被挂起,再添加的操作不会被调度。
*/
- (void)pauseBtnDidClick:(UIButton *)btn{
NSLog(@"队列中操作数:%zd", self.gOpQueue.operationCount);
if ( == self.gOpQueue.operationCount) {
NSLog(@"队列中无操作");
return;
} NSLog(@"3:%d", self.gOpQueue.isSuspended);
self.gOpQueue.suspended = !self.gOpQueue.isSuspended;
NSLog(@"4:%d", self.gOpQueue.isSuspended);
if (self.gOpQueue.isSuspended) {
NSLog(@"队列挂起");
[btn setTitle:@"继续"
forState:UIControlStateNormal];
}else{
NSLog(@"队列继续");
[btn setTitle:@"挂起"
forState:UIControlStateNormal];
}
} /**
取消队列中所有的操作。
不会取消正在执行中的操作。
不会影响队列的挂起状态
*/
- (void)cancelAllBtnDidClick:(UIButton *)btn{
if ( == self.gOpQueue.operationCount) {
NSLog(@"队列中无操作");
return;
} NSLog(@"取消队列中所有操作,此方法不会改变队列挂起状态");
[self.gOpQueue cancelAllOperations]; NSLog(@"1:%d", self.gOpQueue.isSuspended);
self.gOpQueue.suspended = !self.gOpQueue.isSuspended;
NSLog(@"2:%d", self.gOpQueue.isSuspended);
} /** 默认是:异步,并发 */
- (void)aysncCon{
NSOperationQueue *lQueue = [[NSOperationQueue alloc] init];
for (int i = ; i < ; ++i) {
[lQueue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"%d,%@", i, [NSThread currentThread]);
}];
}
} /** 最大并发数:The maximum number of queued operations that can execute at the same time.*/
- (void)maxConCount{
NSOperationQueue *lQueue = [[NSOperationQueue alloc] init];
lQueue.maxConcurrentOperationCount = ;
for (int i = ; i < ; ++i) {
[lQueue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"%d,%@", i, [NSThread currentThread]);
}];
} self.gOpQueue = lQueue;
} /** 常用:子线程耗时,主线程更新UI */
- (void)oftenUse{
NSOperationQueue *lQ = [[NSOperationQueue alloc] init]; [lQ addOperationWithBlock:^{
NSLog(@"耗时操作开始,%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:];
NSLog(@"耗时操作结束"); [[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"主线程更新UI,%@",
[NSThread currentThread]);
}]; }];
} /** 设置依赖 */
- (void)setUpDependence{
NSOperationQueue *lQ = [[NSOperationQueue alloc] init]; [lQ addOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"do something,%@",
[NSThread currentThread]);
}]; NSBlockOperation *lOp1 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"1:登录,%@",
[NSThread currentThread]);
}]; NSBlockOperation *lOp2 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"2:购买点券,%@",
[NSThread currentThread]);
}]; NSBlockOperation *lOp3 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"3:使用点券,%@",
[NSThread currentThread]);
}]; NSBlockOperation *lOp4 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"4:返回结果,%@",
[NSThread currentThread]);
}]; [lOp2 addDependency:lOp1];
[lOp3 addDependency:lOp2];
[lOp4 addDependency:lOp3]; //下面加的话会循环依赖,导致任何操作都无法进行,程序不会崩溃。
// [lOp1 addDependency:lOp4]; [lQ addOperations:@[lOp4, lOp3] waitUntilFinished:NO];
[lQ addOperations:@[lOp2, lOp1] waitUntilFinished:NO];
} /**执行效果如下:
2018-01-05 19:54:31.721539+0800 NSOperationTest[578:156322] come in
2018-01-05 19:54:33.727691+0800 NSOperationTest[578:156342] 0:do others,<NSThread: 0x1c027f740>{number = 3, name = (null)}
2018-01-05 19:54:34.731836+0800 NSOperationTest[578:156342] 1:登录,<NSThread: 0x1c027f740>{number = 3, name = (null)}
2018-01-05 19:54:35.737375+0800 NSOperationTest[578:156342] 2:购买点券,<NSThread: 0x1c027f740>{number = 3, name = (null)}
2018-01-05 19:54:36.742936+0800 NSOperationTest[578:156342] 3:使用点券,<NSThread: 0x1c027f740>{number = 3, name = (null)}
2018-01-05 19:54:37.746491+0800 NSOperationTest[578:156342] 4:show Time,<NSThread: 0x1c027f740>{number = 3, name = (null)}
2018-01-05 19:54:38.764408+0800 NSOperationTest[578:156341] 5:[lQ addOperations:@[lOp4, lOp3] waitUntilFinished:YES];实现了不设置依赖,且我需要最后执行,<NSThread: 0x1c04631c0>{number = 4, name = (null)}
*/
- (void)waitUntilFinished{
NSOperationQueue *lQ = [[NSOperationQueue alloc] init]; NSLog(@"come in");
NSBlockOperation *lOp0 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"0:do others,%@",
[NSThread currentThread]);
}]; NSBlockOperation *lOp1 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"1:登录,%@",
[NSThread currentThread]);
}]; NSBlockOperation *lOp2 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"2:购买点券,%@",
[NSThread currentThread]);
}]; NSBlockOperation *lOp3 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"3:使用点券,%@",
[NSThread currentThread]);
}]; NSBlockOperation *lOp4 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"4:show Time,%@",
[NSThread currentThread]);
}]; NSBlockOperation *lOp5 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:]; NSLog(@"5:[lQ addOperations:@[lOp4, lOp3] waitUntilFinished:YES];实现了不设置依赖,且我需要最后执行,%@",
[NSThread currentThread]);
}]; [lOp2 addDependency:lOp1];
[lOp3 addDependency:lOp2];
[lOp4 addDependency:lOp3]; //执行顺序跟在数组中的顺序无关
//waitUntilFinished:If YES, the current thread is blocked until all of the specified operations finish executing. If NO, the operations are added to the queue and control returns immediately to the caller.(If YES,当前线程会被阻塞,直到数组中所有操作执行完毕。下局代码是直到lOp5执行完毕,才会执行后续操作)
[lQ addOperations:@[lOp0] waitUntilFinished:YES]; [lQ addOperations:@[lOp2, lOp1] waitUntilFinished:NO];
[lQ addOperations:@[lOp4, lOp3] waitUntilFinished:YES]; [lQ addOperation:lOp5];
} @end

多线程之NSOperation小结的更多相关文章

  1. 多线程之NSOperation

    关于多线程会有一系列如下:多线程之概念解析 多线程之pthread, NSThread, NSOperation, GCD 多线程之NSThread 多线程之NSOperation 多线程之GCD

  2. iOS多线程之NSOperation详解

    使用NSOperation和NSOperationQueue进行多线程开发,只要将一个NSOperation(实际开发中需要使用其子类 NSInvocationOperation,NSBlockOpe ...

  3. 多线程之NSOperation简介

    在iOS开发中,为了提升用户体验,我们通常会将操作耗时的操作放在主线程之外的线程进行处理.对于正常的简单操作,我们更多的是选择代码更少的GCD,让我们专注于自己的业务逻辑开发.NSOperation在 ...

  4. 多线程之NSOperation和NSOperationQueue

    这篇文章里我将不过多的谈及理论知识,这些东西会的自然会,不会的,看多了也是云里雾里.下面我讲更多的用代码+注释的方式来讲如何使用NSOperation和NSOperationQueue. 1.NSOp ...

  5. iOS-多线程之NSOperation

    前言 这篇文章主要讲NSOperation的使用. What 使用NSOperation和NSOperationQueue进行多线程开发类似于线程池,只要将一个NSOperation(实际开发中需要使 ...

  6. IOS多线程之NSOperation学习总结

    NSOperation简介 1.NSOperation的作用 配合使用NSOperation和NSOperationQueue也能实现多线程编程 2.NSOperation和NSOperationQu ...

  7. iOS多线程之NSOperation,NSOperationQueue

    使用 NSOperation的方式有两种, 一种是用定义好的两个子类: NSInvocationOperation 和 NSBlockOperation. 另一种是继承NSOperation 如果你也 ...

  8. (五十六)iOS多线程之NSOperation

    NSOpertation是一套OC的API,是对GCD进行的Cocoa抽象. NSOperation有两种不同类型的队列,主队列和自定义队列. 主队列运行于主线程上,自定义队列在后台运行. [NSBl ...

  9. iOS开发多线程之NSOperation

    NSInvocationOperation The NSInvocationOperationclass is a concrete subclass of NSOperationthat you u ...

随机推荐

  1. python学习之【第七篇】:Python中的集合及其所具有的方法

    1.前言 python中的集合set与列表类似,它们最大的区别是集合内不允许出现重复元素,如果在定义时包含重复元素,会自动去重. 集合是无序的,集合中的元素必须是不可变类型.集合可以作为字典的key. ...

  2. 如何在双向绑定的Image控件上绘制自定义标记(wpf)

    我们的需求是什么? 答:需要在图片上增加一些自定义标记,例如:2个图片对比时,对相同区域进行高亮. 先上效果图: 设计思路 1.概述 1.通过TargeUpdated事件,重新绘制图片进行替换. 2. ...

  3. NOIP 模拟17

    最近状态有些不对劲,总是出现各种各样的小错误...... 这次可以说是很水的一套题(T3神仙题除外),T1就是一个优化的暴力,考场上打了一个n的四次方的程序,在距考试结束还有5分钟的时候猜想出来正解, ...

  4. 「POJ 3268」Silver Cow Party

    更好的阅读体验 Portal Portal1: POJ Portal2: Luogu Description One cow from each of N farms \((1 \le N \le 1 ...

  5. python_day2(列表,元组,字典,字符串)

    1.bytes数据类型 msg = '我爱北京天安门' print(msg.encode(encoding="utf-8")) print(msg.encode(encoding= ...

  6. 算法编程题积累(3)——腾讯笔试"构造回文“问题

    首先理解题意,回文串的特点:倒序后跟原串相同.故而可以将原串看成向一个回文串在任意位置添加任意字符后形成的字符串,也就是说原串中存在一段未必连续的回文序列. 通过分析可以知道AC本题的核心思路:求出回 ...

  7. c#Func委托

    public delegate TResult Func<in T, out TResult>(T arg); 参数类型 T:此委托方法的参数类型 TResult:此委托方法的返回值类型 ...

  8. 配置SElinux环境,将SELinux设置为enforcing

    SELinux是 美国国家安全局 (NSA) 对于 强制访问控制的实现 =>可以使root受限的权限 关闭SELinux=>修改配置文件,永久生效; sed -i 's/SELINUX=e ...

  9. 100天搞定机器学习|Day56 随机森林工作原理及调参实战(信用卡欺诈预测)

    本文是对100天搞定机器学习|Day33-34 随机森林的补充 前文对随机森林的概念.工作原理.使用方法做了简单介绍,并提供了分类和回归的实例. 本期我们重点讲一下: 1.集成学习.Bagging和随 ...

  10. 安卓手机运行fedora

    安卓手机使用容器运行其他linux,一般两种: 1. termux + rootfs.img + proot,依赖api>=21,不必root但受限. 2. linuxdeploy + proo ...