相对于GCD来说,Operation Queues会更加复杂一些,但是可以为operation之间添加依赖关系、暂停和恢复Operation Queue、取消正在执行的operation。这是GCD所做不到的。
Operation
要使用Operation Queue技术,需要使用NSOperation
类来封装需要执行的任务。但是,NSOperation
本身不能实例化,所以必须使用系统本身就实现好的两个子类:NSInvocationOperation
和NSBlockOperation
,或者自己创建一个NSOperation
的子类。
NSInvocationOperation
使用- (nullable instancetype)initWithTarget:(id)target selector:(SEL)sel object:(nullable id)arg;
创建一个NSInvocationOperation
对象。这个对象可以随时更换SEL
,例如:
operation.invocation.selector = @selector(operationMethod:);
NSBlockOperation
使用+ (instancetype)blockOperationWithBlock:(void (^)(void))block;
创建一个NSBlockOperation
对象。
自定义NSOperation
必须重写的方法:
-
- (void)start
是一个operation的起点。 -
- (BOOL)isConcurrent
是否是并发的,返回YES
; -
- (BOOL)isExecuting
是否开始执行; -
- (BOOL)isFinished
是否执行完成;
其中第3、4个方法所代表的属性值发生变化时,我们需要手动触发KVO
通知,以便外界能观察到这些值的变化。例如:
[self willChangeValueForKey:@"isFinished"];
_isFinished = YES;
[self didChangeValueForKey:@"isFinished"];
</br>
注意:为了支持operation的取消操作,在执行操作时要定期检查isCancelled
的值,一旦返回YES
则立刻停止之后的操作。当然也可以自己重写- (void)cancel
方法来取消正在执行的操作,不过要记得调用[super cancel]
。
CompletionBlock
使用setCompletionBlock:
方法设置operation的CompletionBlock
。
从字面意思上看很容易理解CompletionBlock
的作用,但是值得一提的是,当一个operation调用了cancel
方法取消后,也会执行CompletionBlock
,所以需要在block中判断operation是否被取消。
添加依赖关系
使用NSOperation
对象的两个方法:
- (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op;
为operation添加依赖关系。例如:[A addDependency:B]
表示A依赖于B,所以A需要等B执行完后才会开始执行。
注意:两个有依赖关系的operation不一定需要在同一个OperationQueue
对象之中。
设置Operation在队列中的优先级
NSOperation
对象使用setQueuePriority:
设置自身在NSOperationQueue
对象中执行的优先级。参数有:
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
};
执行Operation
Operation对象有两种执行方式:
- 直接让对象调用
- (void)start;
方法,但是这种方式并不能保证Operation对象是异步执行的; - 将Operation对象放入
NSOperationQueue
对象中,让NSOperationQueue
的对象帮我们自动执行,OperationQueue会自动为这个 operation创建一个线程,不需要我们自己去实现异步执行。
取消Operation
使用NSOperation
对象调用它的cancel
方法取消这个 operation ,或者调用 NSOperationQueue
对象的 cancelAllOperations
方法取消这个OperationQueue 中所有的operation。
注意:一般情况下正在执行中的operation需要等到下一个检查isCancelled
的位置才会停止,所以最好设置CompletionBlock
来判断operation的isCancelled
的值再决定是否执行operation完成后的操作。
例如:在一个根据用户实时输入的文字来进行搜索并展示返回结果的案例中,因为operation是并发的,假如用户先后输入了A
、B
、C
,而返回的结果的顺序不一定是A
、AB
、ABC
,所以最后展示的结果不一定是ABC
的搜索结果,解决方法就是在用户输入文字后取消之前的operation,而在CompletionBlock
中判断isCancelled
的值,只有没被取消再使用主线程更新UI。
暂停和恢复OperationQueue
使用NSOperationQueue
对象调用setSuspended:
来实现暂停或恢复OperationQueue,不过正在执行的Operation并不能暂停,除非直接取消Operation。
</br>
想更深入的了解Operation Queues
可以查看AFNetworking
的AFURLConnectionOperation
代码。
网友评论