概述
NSOperation 是蘋果公司對 GCD 的封裝,完全面向?qū)ο?,所以使用起來更好理解?大家可以看到 NSOperation 和 NSOperationQueue 分別對應 GCD 的 任務 和 隊列 。
操作步驟主要就兩步:
- 將要執(zhí)行的任務封裝到
NSOperation中; - 將此任務添加到
NSOperationQueue中。
添加任務
NSOperation 只是一個抽象類,所以不能封裝任務。但它有 2 個子類用于封裝任務。分別是:NSInvocationOperation 和 NSBlockOperation 。創(chuàng)建一個 Operation 后,需要調(diào)用 start 方法來啟動任務,它會 默認在當前隊列同步執(zhí)行。當然你也可以在中途取消一個任務,只需要調(diào)用其 cancel 方法即可。
- NSInvocationOperation :初始化
//1.創(chuàng)建NSInvocationOperation對象 NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil]; //2.開始執(zhí)行 [operation start];
- NSBlockOperation: 初始化
//1.創(chuàng)建NSBlockOperation對象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//2.開始任務
[operation start];
> 這樣添加的任務,會默認在當前線程執(zhí)行。不過```NSBlockOperation```提供了這個方法```addExecutionBlock:```,可以給operation添加多個block,這樣operation中的任務就會**并發(fā)執(zhí)行**,。他會在**主線程和其他多個線程**執(zhí)行這些任務
注:```addExecutionBlock``` 方法必須在 start() 方法之前執(zhí)行,否則就會報錯:
‘*** -[NSBlockOperation addExecutionBlock:]: blocks cannot be added after the operation has started executing or finished'
### 添加隊列
我們通過``` NSOperation``` 對象的``` start() ```方法來啟動這個任務,事實上系統(tǒng)默認是 **同步執(zhí)行** 的。就算是 ```addExecutionBlock``` 方法,也會在 **當前線程和其他線程 中執(zhí)行**,也就是說還是會占用當前線程。這時就要用到隊列 **NSOperationQueue** 了。一般分為兩種隊列:主隊列、其他隊列。**只要添加到隊列,會自動調(diào)用任務的 start() 方法**。
- 主隊列
通過調(diào)用```mainQueue```類方法創(chuàng)建的是為主隊列。
NSOperationQueue *queue = [NSOperationQueue mainQueue];
- 其他隊列
因為主隊列比較特殊。個人覺得是主隊列是單例,所以統(tǒng)一用一個類方法來返回。通過初始化產(chǎn)生的隊列,就是其他隊列。其他隊列的任務會在其他線程并行執(zhí)行
//1.創(chuàng)建一個其他隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//2.創(chuàng)建NSBlockOperation對象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//3.添加多個Block
for (NSInteger i = 0; i < 5; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
}];
}
//4.隊列添加任務
[queue addOperation:operation];
#####需要注意
運行上面代碼,會發(fā)現(xiàn)這里并沒有串行隊列,和GCD并不同。如果想要實現(xiàn),則可以設(shè)置```NSOperationQueue```中```maxConcurrentOperationCount```這個屬性。該屬性是設(shè)置最大并發(fā)數(shù),用來設(shè)置最多可以讓多少個任務同時執(zhí)行。因此設(shè)置為```1```即可。
```NSOperationQueue``` 還有一個快速添加任務的方法,```- (void)addOperationWithBlock:(void (^)(void))block;```這樣就可以添加一個任務到隊列中了,十分方便。
#### 依賴
**場景**
比如有 3 個任務:A: 從服務器上下載一張圖片,B:給這張圖片加個水印,C:把圖片返回給服務器。這時就可以用到依賴了
//1.任務一:下載圖片
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下載圖片 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];
//2.任務二:打水印
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"打水印 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];
//3.任務三:上傳圖片
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"上傳圖片 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];
//4.設(shè)置依賴
[operation2 addDependency:operation1]; //任務二依賴任務一
[operation3 addDependency:operation2]; //任務三依賴任務二
//5.創(chuàng)建隊列并加入任務
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];
使用注意:
- 不能相互依賴, A依賴B,B依賴A,這樣會造成死鎖
- 可以使用方法```removeDependency ```解除依賴
- 依賴是添加到任務上的。因此,依賴是跨隊列的。
> 未完待續(xù)