相對于GCD來說,Operation Queues會更加復雜一些,但是可以為operation之間添加依賴關(guān)系、暫停和恢復Operation Queue、取消正在執(zhí)行的operation。這是GCD所做不到的。
Operation
要使用Operation Queue技術(shù),需要使用NSOperation
類來封裝需要執(zhí)行的任務。但是,NSOperation
本身不能實例化,所以必須使用系統(tǒng)本身就實現(xiàn)好的兩個子類:NSInvocationOperation
和NSBlockOperation
,或者自己創(chuàng)建一個NSOperation
的子類。
NSInvocationOperation
使用- (nullable instancetype)initWithTarget:(id)target selector:(SEL)sel object:(nullable id)arg;
創(chuàng)建一個NSInvocationOperation
對象。這個對象可以隨時更換SEL
,例如:
operation.invocation.selector = @selector(operationMethod:);
NSBlockOperation
使用+ (instancetype)blockOperationWithBlock:(void (^)(void))block;
創(chuàng)建一個NSBlockOperation
對象。
自定義NSOperation
必須重寫的方法:
-
- (void)start
是一個operation的起點。 -
- (BOOL)isConcurrent
是否是并發(fā)的,返回YES
; -
- (BOOL)isExecuting
是否開始執(zhí)行; -
- (BOOL)isFinished
是否執(zhí)行完成;
其中第3、4個方法所代表的屬性值發(fā)生變化時,我們需要手動觸發(fā)KVO
通知,以便外界能觀察到這些值的變化。例如:
[self willChangeValueForKey:@"isFinished"];
_isFinished = YES;
[self didChangeValueForKey:@"isFinished"];
</br>
注意:為了支持operation的取消操作,在執(zhí)行操作時要定期檢查isCancelled
的值,一旦返回YES
則立刻停止之后的操作。當然也可以自己重寫- (void)cancel
方法來取消正在執(zhí)行的操作,不過要記得調(diào)用[super cancel]
。
CompletionBlock
使用setCompletionBlock:
方法設置operation的CompletionBlock
。
從字面意思上看很容易理解CompletionBlock
的作用,但是值得一提的是,當一個operation調(diào)用了cancel
方法取消后,也會執(zhí)行CompletionBlock
,所以需要在block中判斷operation是否被取消。
添加依賴關(guān)系
使用NSOperation
對象的兩個方法:
- (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op;
為operation添加依賴關(guān)系。例如:[A addDependency:B]
表示A依賴于B,所以A需要等B執(zhí)行完后才會開始執(zhí)行。
注意:兩個有依賴關(guān)系的operation不一定需要在同一個OperationQueue
對象之中。
設置Operation在隊列中的優(yōu)先級
NSOperation
對象使用setQueuePriority:
設置自身在NSOperationQueue
對象中執(zhí)行的優(yōu)先級。參數(shù)有:
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
};
執(zhí)行Operation
Operation對象有兩種執(zhí)行方式:
- 直接讓對象調(diào)用
- (void)start;
方法,但是這種方式并不能保證Operation對象是異步執(zhí)行的; - 將Operation對象放入
NSOperationQueue
對象中,讓NSOperationQueue
的對象幫我們自動執(zhí)行,OperationQueue會自動為這個 operation創(chuàng)建一個線程,不需要我們自己去實現(xiàn)異步執(zhí)行。
取消Operation
使用NSOperation
對象調(diào)用它的cancel
方法取消這個 operation ,或者調(diào)用 NSOperationQueue
對象的 cancelAllOperations
方法取消這個OperationQueue 中所有的operation。
注意:一般情況下正在執(zhí)行中的operation需要等到下一個檢查isCancelled
的位置才會停止,所以最好設置CompletionBlock
來判斷operation的isCancelled
的值再決定是否執(zhí)行operation完成后的操作。
例如:在一個根據(jù)用戶實時輸入的文字來進行搜索并展示返回結(jié)果的案例中,因為operation是并發(fā)的,假如用戶先后輸入了A
、B
、C
,而返回的結(jié)果的順序不一定是A
、AB
、ABC
,所以最后展示的結(jié)果不一定是ABC
的搜索結(jié)果,解決方法就是在用戶輸入文字后取消之前的operation,而在CompletionBlock
中判斷isCancelled
的值,只有沒被取消再使用主線程更新UI。
暫停和恢復OperationQueue
使用NSOperationQueue
對象調(diào)用setSuspended:
來實現(xiàn)暫停或恢復OperationQueue,不過正在執(zhí)行的Operation并不能暫停,除非直接取消Operation。
</br>
想更深入的了解Operation Queues
可以查看AFNetworking
的AFURLConnectionOperation
代碼。