NSOperationQueue
有兩種不同類型的隊列:主隊列和自定義隊列。主隊列運行在主線程之上,而自定義隊列在后臺執(zhí)行。在兩種類型中,這些隊列所處理的任務(wù)都使用NSOperation
的子類來表述。
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; //主隊列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //自定義隊列 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
//任務(wù)執(zhí)行
}];
[queue addOperation:operation];
我們可以通過設(shè)置 maxConcurrentOperationCount
屬性來控制并發(fā)任務(wù)的數(shù)量,當(dāng)設(shè)置為 1時, 那么它就是一個串行隊列。主對列默認(rèn)是串行隊列,這一點和 dispatch_queue_t 是相似的。
NSOperation
你可以使用系統(tǒng)提供的一些現(xiàn)成的NSOperation的子類, 如 NSBlockOperation、NSInvocationOperation等(如上例子)。你也可以實現(xiàn)自己的子類, 通過重寫 main
或者start方法 來定義自己的 operations 。使用 main方法非常簡單,開發(fā)者不需要管理一些狀態(tài)屬性(例如 isExecuting 和 isFinished),當(dāng) main 方法返回的時候,這個 operation 就結(jié)束了。這種方式使用起來非常簡單,但是靈活性相對重寫 start 來說要少一些, 因為main方法執(zhí)行完就認(rèn)為operation結(jié)束了,所以一般可以用來執(zhí)行同步任務(wù)。
@implementation YourOperation
- (void)main{
// 任務(wù)代碼 ...
}
@end
如果你希望擁有更多的控制權(quán),或者想在一個操作中可以執(zhí)行異步任務(wù),那么就重寫 start方法, 但是注意:這種情況下,你必須手動管理操作的狀態(tài), 只有當(dāng)發(fā)送 isFinished的 KVO 消息時,才認(rèn)為是 operation 結(jié)束。
@implementation YourOperation - (void)start{
self.isExecuting = YES;
// 任務(wù)代碼 ...
} - (void)finish //異步回調(diào)
{
self.isExecuting = NO;
self.isFinished = YES;
}
@end
當(dāng)實現(xiàn)了start方法時,默認(rèn)會執(zhí)行start方法,而不執(zhí)行main方法。為了讓操作隊列能夠捕獲到操作的改變,需要將狀態(tài)的屬性以配合 KVO的方式進行實現(xiàn)。如果你不使用它們默認(rèn)的 setter 來進行設(shè)置的話你就需要在合適的時候發(fā)送合適的 KVO消息。
需要手動管理的狀態(tài)有:
isExecuting代表任務(wù)正在執(zhí)行中
isFinished代表任務(wù)已經(jīng)執(zhí)行完成
isCancelled代表任務(wù)已經(jīng)取消執(zhí)行手動的發(fā)送 KVO消息, 通知狀態(tài)更改如下 :
[self willChangeValueForKey:@"isCancelled"];
_isCancelled = YES;
[self didChangeValueForKey:@"isCancelled"];
為了能使用操作隊列所提供的取消功能,你需要在長時間操作中時不時地檢查 isCancelled屬性, 比如在一個長的循環(huán)中:
@implementation MyOperation
- (void)main{
while (notDone && !self.isCancelled)
{
// 任務(wù)處理
}
}
@end