前几天整理了一下关于多线程GCD
的相关内容, 苹果还有一种高级的多线程处理方式是使用NSOperation
, 它拥有着和GCD
同样的特点即不需要手动管理线程的声明周期, 而是让开发者把重点关注在自己的方法处理上, 并且NSOperation
还有着可以手动控制开始, 取消操作等优点。NSOperation
完全是Objective-C
对象的形式, 个人感觉NSOperation
应该是苹果主推的多线程管理框架, = = 但基本上面试问GCD
的还是多一点。NSOperation
的官方文档
NSOperation
Because the NSOperation class is an abstract class, you do not use it directly but instead subclass or use one of the system-defined subclasses (NSInvocationOperation or NSBlockOperation) to perform the actual task.
苹果的官方原话, 意思是说NSOperation
是一个抽象类, 不能直接被使用, 你可以使用它的子类NSInvocationOperation
和NSBlockOperation
。
基本使用
1 |
|
一种是target action
的形式, 一种是block
回调的形式, 接下来运行一下:
1 |
|
可以看到, 在直接使用NSInvocationOperation
或NSBlockOperation
时, 它们都是运行在主线程之上的。
NSBlockOperation
但是NSBlockOperation
稍微有点特殊, 他可以追加任务:
1 |
|
所以NSBlockOperation
中的任务不一定是运行在主线程之上的。
自定义NSOperation子类
既然NSOperation
是一个抽象类, 我们不妨自己实现一个, 先看一下它的方法和属性:
1 |
|
属性方面大多数是任务的状态, 如果需要观察状态我们可以用kvo
的方式监听一下。方法包含开始取消还有一个main
, 根据NSInvocationOperation
与NSBlockOperation
的使用方法来看, 这个main
方法很可能是我们需要实现功能的方法, 而NSInvocationOperation
与NSBlockOperation
是以回调的形式把main
的实现留给我们。可以去官方文档看一下:
Performs the receiver’s non-concurrent task.
The default implementation of this method does nothing. You should override this method to perform the desired task. In your implementation, do not invoke super. This method will automatically execute within an autorelease pool provided by NSOperation, so you do not need to create your own autorelease pool block in your implementation. If you are implementing a concurrent operation, you are not required to override this method but may do so if you plan to call it from your custom start method.
确实是这样的, main
方法默认不做任何事情, 我们需要重写main
方法来执行我们自己需要执行的任务, 并且是并发类型, 释放也不需要我们关心。接来下就可以实现一些自定义的方法:
自定义任务实现
1 |
|
打印结果:
1 |
|
这样就可以观察到任务的执行状态及所在线程情况, 还是运行在主线程之上的, Operation的取消并不能取消已经在运行的Operation。
依赖
在对剩余的属性及方法进行一波分析:
1 |
|
先看这两个方法addDependency
, removeDependency
字面意思是添加依赖和移除依赖, 参数是另一个NSoperation
我们可以尝试写一下:
1 |
|
然后程序崩溃了:
1 |
|
这里大概是说有一个Operation没有准备好运行, 刚巧上面有一个ready
的属性可以判断试试:
1 |
|
果然, 程序不会在崩溃了, 如果我们将Operation的倒序执行的话:
1 |
|
结果:
1 |
|
可以看到, 这些Operation之间是有相互依赖关系的, 只有依赖的Operation执行完毕之后才能进行另一个Operation, 往往我的业务中也有很多这样的特点, 比如网络请求的依赖等。
还剩下一些优先级参数和同步异步参数会放到NSOperationQueue
中讲到。
NSOperationQueue
由于之前的操作都是在主线程上进行(NSBlockOperation
有例外, 他的add方法不一定是在主线程, 有可能是其他线程, 由于我只专注了自定义Operation疏忽了对系统的两个对象的使用), 感觉和多线程没有什么关系, 如果要实现多线程编程, 还需要借助另外一个对象NSOperationQueue
。
基础操作
首先我们来创建一个NSOperationQueue
, 添加两个Operation:
1 |
|
打印结果:
1 |
|
可以看到, NSOperationQueue
默认是一个异步并发的队列, 并且加入到队列中的Operation不用执行start
方法, 队列会帮我们自动执行。类似于GCD
的调度组。
suspended
可以使用suspended
使队列中的任务暂停:
1 |
|
打印结果:
1 |
|
这样也说明了任务被添加之后就开始了。
maxConcurrentOperationCount
maxConcurrentOperationCount
这个属性可以控制最大的并发任务数量, 如果将这个值设置为1则可实现串行:
1 |
|
可以看到结果是异步的顺序输出:
1 |
|
waitUntilFinished
之前说还有一部分NSOperation
的属性和方法没有分析, 其实他们在队列对象中也有类似的方法, 比如waitUntilFinished
, 他主要是起到一个阻塞当前线程的效果, 等待到完成之后才会执行其他任务:
1 |
|
这个得到结果是这样的
1 |
|
当然, 如果我们不需要异步并发的操作, 可以直接使用NSOperation
对象, 然后调用这些方法。
queuePriority
queuePriority
, 任务优先级, 默认创建的任务都是Normal级别, 可以验证一下:
1 |
|
其余的待补充…