NSOperation
简介
-
操作就是一个任务
-
作用
- 配合NSOperation和NSOperationQueue实现多线程编程
-
实现多线程的具体步骤
- 先将需要执行的操作封装到一个NSOperation对象中
- 然后将NSOperation对象添加到NSOperationQueue中
- 系统会自动将NSOperationQueue中的NSOperation取出来
- 将取出的NSOperation封装的操作放到一条新的线程中执行
-
NSOperation的子类
- NSOperation抽象类,并不具备封装操作的能力,必须使用它的子类
- 使用NSOperation子类的方式
- NSInvocationOperation
- NSBlockOperation
- 自定义子类继承NSOperation,实现内部相应的方法
- NSInvocationOperation
- 了解,本身不好用,开发中不经常用,swift里面没有InvocationOperation的API了
封装操作的几种方式
-
操作:一个op对象
-
任务:方法里面的代码
-
NSInvocationOperation
- 创建一个操作对象NSInvocationOperation alloc]initWithTarget:selector:object:
- 第一个参数:目标对象self
- 第二个参数:要调用的方法
- 第三个参数:要调用方法需要接收的参数
- 执行操作
- start开始执行操作
- 没有开子线程,在当前线程中串行执行
- 必须要和队列结合起来使用,才能开线程
- 创建一个操作对象NSInvocationOperation alloc]initWithTarget:selector:object:
-
NSBlockOperation
- 创建操作对象NSBlockOperation blockOperationWithBlock:^{}
- 执行操作
- start
- 没有开子线程,在当前线程中串行执行
-
特殊
:对象方法addExcutionBlock追加任务,可能开子线程的- 注意点:NSBlockOperation在使用的时候,如果一个操作中任务的数量大于1,那么就会开启子线程和当前线程一起并发执行block中的代码(任务)
操作队列的基本使用
- NSInvocationOperation
- 回顾GCD中的队列
- 并发队列
- 自己创建
- 全局并发队列
- 串行队列
- 自己创建
- 主队列
- 并发队列
- NSOperation队列
- 主队列 mainQueue== GCD中串行队列中的主队列
- 串行
- 凡是在主队列中的任务都在主线程中执行
- 非主队列 alloc]init
- 默认情况下是并发队列
- 可以设置为串行队列(最大并发数)
- 可以开多条线程,并发执行任务
- 主队列 mainQueue== GCD中串行队列中的主队列
- 基本使用
- 创建一个非主队列alloc]init
- 封装操作NSInvocationOperation alloc]initWithTarget:selector:object:
- 添加操作到队列中addOperation
- 为什么不调用start方法也能执行操作呢?因为addOperation内部会调用start方法】
- 回顾GCD中的队列
- NSBlockOperation
- 创建队列alloc]init
- 封装操作blockOperationWithBlock:
- 添加操作到队列中 addOperation
- 并发执行任务的
- 追加任务 addExecutionBlock:^{}
- 简便方法
- queue addOperationWithBlock:^{}
- 内部做了两件事情
- 创建操作
- 把操作添加到队列
- 缺点:拿不到操作对象,无法设置操作
NSOperation属性
-
最大并发数(默认是-1)
- 创建队列
- 封装操作
- 添加操作到队列中
- 要求:按顺序执行任务,改为串行队列
- 设置最大并发数(同一时间最多可以执行的任务的数量)maxConcurrentOperationCount = 1
- 设置最大并发数的时候,要保证一个操作里面就有一个任务
- 追加任务,最大并发数没有用了,因为追加任务大于1的时候,会自动开子线程,并发执行任务
- 最大并发数不能设置为0,一般设置为5~6
- 默认是-1,-1是指数量不受限制
-
suspended暂停任务
- 创建队列
- 封装操作
- 设置最大并发数 = 1(便于观察suspend)
- 添加操作到队列中
- 注意点:开几条线程不是有操作数量决定的
- suspended是BOOL类型
- 定义一个队列属性
- storyboard中添加控件
- 开始
- 暂停
- setSuspended:YES
- 没有立刻停住,操作是原子性的,block里的任务是一个整体,只要开始就停不下来,暂停是针对操作来说的
- 暂停操作,只能暂停后面尚未执行的操作,对于当前处于执行状态的任务是没有影响的
- 恢复
- setSuspended:NO
- 取消
- cancelAllOperations队列里的所有的操作都会调用cancel方法
- 取消之后,就不能恢复了
- 取消操作只能取消后面尚未执行的操作,对于当前处于执行状态的任务是没有影响的
自定义操作
- 新建一个继承自NSOperation的类
- 创建队列
- 封装操作
- 敲不出来alloc]initWithTarget: 和blockOperationWithBlock:
- 只能用alloc]init
- main方法里面封装操作,自定义的类里面重写main方法
- 把操作添加到队列里面去
- addOperation
- 好处:
- 能够提高代码的复用性,把代码放到main方法里
- 信息隐蔽
- 问题:
- 不会马上取消
- 产生原因
- 三个for循环是一个整体,是同一个操作,是没有办法取消的
- 拿到队列里的所有操作,调用cancel方法
- 解决:每当执行完一个耗时操作之后,就检查当前的操作是否已经被取消,如果已经取消那么久结束任务
if(self.isCancelled){
return;
}
- 怎么达到点击取消,立刻就取消,把判断方法放到for循环里面,但是性能不好,不推荐使用
操作队列中的依赖和监听(掌握)
- 创建队列alloc]init
- 添加三个操作
- NSBlockOperation blockOperatinoWithBlock:
-
怎么实现类似GCD栅栏函数,队列组功能?
- 三个操作执行完毕后,执行任务4
-
设置依赖
- 任务4 addDependency 任务1
- 任务4 addDependency 任务2
- 任务4 addDependency 任务3
- 可以设置
多重依赖
(按照4321的顺序执行)- 任务1 addDependency 任务2
- 任务2 addDependency 任务3
- 任务3 addDependency 任务4
- 注意:不能设置循环依赖
- 如果有多个队列,可以实现
跨队列依赖
- 任务5添加到第二个队列中
- 可以让任务4依赖于任务5
-
设置监听
- .completionBlock = ^{}
- 添加操作到队列
- addOperation
线程间通信
- 下载图片在子线程,回到主线程刷新UI
- 创建队列 alloc]init
- 封装操作
- NSBlockOperation blockOperationWithBlock:
- 确定URL
- 把图片的二进制数据下载到本地
- 转换格式
- 添加操作到队列
- addOperation
- 添加到队列之后,才会回过头来执行上面的block块
- 回到主线程设置图片
- 方式一:可以混合使用GCD
- 方式二:
NSOperationQueue mainQueue]addOperationWithBlock:^{
self.imageV.image = image ;
}
-
修改配置文件
-
怎么使用操作队列下载两张图片合成一张图片?
GCD和NSOperation对比
- GCD是纯C语言的API,而操作队列则是OC的对象
- 在GCD中任务用block块来表示,而block块是一个轻量级的数据结构;相反操作队列中的操作NSOperation对象则是一个更加重量级的OC对象
- 开发中使用GCD还是NSOperation需要看具体的情况
- 看个人喜好,一般而言,实现同一种功能,采用封装程度更高的NSOperation
- 如果开发中,只是简单的开线程执行任务,可以使用GCD
- 如果处理多个任务,并且有依赖关系,可以使用NSOperation
NSOperation和NSOperationQueue的好处
- NSOperationQueue可以方便的调用cancel方法来取消某一个操作,而GCD中的任务是无法被取消的(安排好任务之后就不管了)
- NSOperation可以方便的指定操作间的依赖关系
- NSOperation可以通过KVO提供对NSOperation对象的精细控制(如监听当前操作是否被取消或是否已经完成)
- cancelld finished
- 注册添加监听
- download addObserver:options:旧值还是新值 context:
- 调用方法observerValueForKeyPath:ofObject:change:context:
- NSOperation可以方便的指定操作的优先级,操作优先级表示此操作与队列中的其他操作之间的优先关系,优先级高的操作先执行,优先级低的后执行
- 通过自定义NSOperation的子类可以实现操作重用
网友评论