NSOperation和NSOperationQueue
NSOperation
NSOperation 是个抽象类,不能用来封装操作。我们只有使用它的子类来封装操作。我们有三种方式来封装操作。
1、使用子类 NSInvocationOperation
2、使用子类 NSBlockOperation
3、自定义继承自 NSOperation 的子类,通过实现内部相应的方法来封装操作。
在不使用 NSOperationQueue,单独使用 NSOperation 的情况下系统同步执行操作,
注意
1、在其他线程中单独使用子类 NSInvocationOperation,操作是在当前调用的其他线程执行的,并没有开启新线程。
2、
NSBlockOperation 执行一个操作的情况下,操作是在当前线程执行的,并没有开启新线程。
NSBlockOperation 还提供了一个方法 addExecutionBlock:
,通过 addExecutionBlock:
就可以为 NSBlockOperation 添加额外的操作。这些操作(包括blockOperationWithBlock
中的操作)可以在不同的线程中同时(并发)执行。只有当所有相关的操作已经完成执行时,才视为完成。
如果NSBlockOperation已经执行结束或正在执行,addExecutionBlock
就会崩溃
The block should take no parameters and have no return value.
3、自定义继承自 NSOperation 的子类
重写main方法,main 执行完返回的时候,这个操作就结束了。如果需要复用,就要让runloop一直存活下去。
类型 | API | 说明 |
---|---|---|
取消 | - (void)cancel; |
实质是标记 isCancelled 状态 |
判断操作状态方法 | - (BOOL)isFinished; |
判断操作是否已经结束 |
- (BOOL)isCancelled; |
判断操作是否已经标记为取消 | |
- (BOOL)isExecuting; |
判断操作是否正在在运行 | |
- (BOOL)isReady; |
判断操作是否处于准备就绪状态,这个值和操作的依赖关系相关 | |
操作同步 | - (void)waitUntilFinished; |
阻塞当前线程,直到该操作结束。可用于线程执行顺序的同步 |
添加操作 | - (void)setCompletionBlock:(void (^)(void))block; |
completionBlock 会在当前操作执行完毕时执行 completionBlock |
NSOperationQueue
类;型 | API | 说明 |
---|---|---|
主队列 | mainQueue | 凡是添加到主队列中的操作,都会放到主线程中执行(注:不包括操作使用addExecutionBlock:添加的额外操作,额外操作可能在其他线程执行) |
队列并发数控制 | maxConcurrentOperationCount | 控制的不是并发线程的数量,而是一个队列中同时能并发执行的最大操作数。而且一个操作也并非只能在一个线程中运行。开启线程数量是由系统决定的,不需要我们来管理 |
maxConcurrentOperationCount = 1 | 并发数为1,串行执行 | |
maxConcurrentOperationCount 大于1或者为 -1 | 并发执行 |
方法说明:
类型 | API | 说明 |
---|---|---|
取消 | - (void)cancelAllOperations; |
可以取消队列的所有操作 |
判断操作状态方法 | - (BOOL)isSuspended; |
判断队列是否处于暂停状态。 YES 为暂停状态,NO 为恢复状态 |
- (void)setSuspended:(BOOL) |
可设置操作的暂停和恢复,YES 代表暂停队列,NO 代表恢复队列 | |
操作同步 | - (void)waitUntilAllOperationsAreFinished; |
阻塞当前线程,直到队列中的操作全部执行完毕 |
- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait; |
向队列中添加操作数组,wait 标志是否阻塞当前线程直到所有操作结束 | |
获取队列 | + (id)currentQueue; |
当前队列 |
+ (id)mainQueue; |
主队列 |
二者结合使用步骤
1、创建操作:先将需要执行的操作封装到一个 NSOperation 对象中。
2、创建队列:创建 NSOperationQueue 对象。
3、将操作加入到队列中:将 NSOperation 对象添加到NSOperationQueue 对象中。
之后,系统就会自动将 NSOperationQueue 中的 NSOperation 取出来,在新线程中执行操作。
使用注意点
操作在队列中的执行顺序
1、操作就绪
当一个操作的所有依赖都已经完成时,操作对象通常会进入准备就绪状态,等待执行。
2、操作优先级(queuePriority)
对于添加到队列中的操作,首先进入准备就绪的状态(就绪状态取决于操作之间的依赖关系),然后进入就绪状态的操作的开始执行顺序(非结束执行顺序)由操作之间相对的优先级决定(优先级是操作对象自身的属性)。
3、操作之间的依赖关系
- (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op;
通过添加操作依赖,可以使操作顺序有序。如操作A依赖操作B,那么在队列中,永远是操作B先执行,然后才执行操作B。
二者关系总结:
如果一个队列中既包含高优先级操作,又包含低优先级操作,并且两个操作都已经准备就绪,那么队列先执行高优先级操作。
如果一个队列中既包含了准备就绪状态的操作,又包含了未准备就绪的操作,未准备就绪的操作优先级比准备就绪的操作优先级高。那么,虽然准备就绪的操作优先级低,也会优先执行。优先级不能取代依赖关系。如果要控制操作间的启动顺序,则必须使用依赖关系。