NSOperation
NSOperation類是用來封裝在單個任務(wù)相關(guān)的代碼和數(shù)據(jù)的抽象類桥温。NSOperation 是蘋果公司對 GCD 的封裝蛹屿,完全面向?qū)ο笠缍梗允褂闷饋砀美斫狻?br>
** 因為它是用來封裝任務(wù)的,大家可以看到 NSOperation 和 NSOperationQueue 分別對應(yīng) GCD 的 任務(wù) 和 隊列拉宗,
但是NSOperation本身又有執(zhí)行多線程的能力跟GCD里的任務(wù)還是有區(qū)別的** 车荔。
操作步驟也很好理解:
- 將要執(zhí)行的任務(wù)封裝到一個 NSOperation 對象中渡冻。
- 將此任務(wù)添加到一個 NSOperationQueue 對象中。
然后系統(tǒng)就會自動在執(zhí)行任務(wù)忧便。
創(chuàng)建任務(wù)
NSOperation 只是一個抽象類族吻,所以不能封裝任務(wù)。但它有 2 個子類用于封裝任務(wù)珠增。分別是:NSInvocationOperation 和 NSBlockOperation 超歌。創(chuàng)建一個 Operation 后,需要調(diào)用 start 方法來啟動任務(wù)切平,它會默認在當前隊列同步執(zhí)行握础。當然你也可以在中途取消一個任務(wù)辐董,只需要調(diào)用其 cancel 方法即可悴品。
#.創(chuàng)建NSInvocationOperation對象
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
//開始執(zhí)行
[operation start];
# 創(chuàng)建一個NSOperation不應(yīng)該直接調(diào)用start方法(如果直接start則會在主線程中調(diào)用)而是應(yīng)該放到NSOperationQueue中啟動。
#.創(chuàng)建NSBlockOperation對象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//開始任務(wù)
[operation start];
注意:之前說過這樣的任務(wù),默認會在當前線程執(zhí)行苔严。但是 NSBlockOperation 還有一個方法:addExecutionBlock: 定枷,通過這個方法可以給 Operation 添加多個執(zhí)行 Block。這樣 Operation 中的任務(wù) 會并發(fā)執(zhí)行届氢,它會 在主線程和其它的多個線程 執(zhí)行這些任務(wù).欠窒。并且ddExecutionBlock 方法必須在 start() 方法之前執(zhí)行,否則就會報錯退子。
# 創(chuàng)建NSBlockOperation對象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
# 添加多個Block
for (NSInteger i = 0; i < 5; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
}];
}
#開始任務(wù)岖妄,你會發(fā)現(xiàn),會在多個線程中打印寂祥,其中包括主線程荐虐。
[operation start];
自定義Operation
除了上面的兩種 Operation 以外,我們還可以自定義 Operation丸凭。自定義 Operation 需要繼承 NSOperation 類福扬,并實現(xiàn)其 main() 方法,因為在調(diào)用 start() 方法的時候惜犀,內(nèi)部會調(diào)用 main() 方法完成相關(guān)邏輯铛碑。所以如果以上的兩個類無法滿足你的欲望的時候,你就需要自定義了虽界。你想要實現(xiàn)什么功能都可以寫在里面汽烦。除此之外,你還需要實現(xiàn) cancel() 在內(nèi)的各種方法莉御。
創(chuàng)建隊列
我們可以調(diào)用一個 NSOperation 對象的 start() 方法來啟動這個任務(wù)刹缝,這個默認是 同步執(zhí)行 的。就算是 addExecutionBlock 方法颈将,也會在 當前線程和其他線程 中執(zhí)行梢夯,也就是說還是會占用當前線程。如果你不想這個任務(wù)在主線程中執(zhí)行(代碼默認情況下都在主線程中執(zhí)行晴圾。)這是就要用到隊列 NSOperationQueue 颂砸。按類型來說的話一共有兩種類型:主隊列、其他隊列死姚。只要添加到隊列人乓,會自動調(diào)用任務(wù)的 start() 方法。
- 主隊列
主隊列是串行隊列都毒,添加到主隊列的任務(wù)都會一個接一個地排著隊在主線程處理色罚。
# 獲取到主隊列
NSOperationQueue *queue = [NSOperationQueue mainQueue];
-
其他創(chuàng)建的隊列
主隊列比較特殊,所以會單獨有一個類方法來獲得主隊列账劲。并且其他隊列的任務(wù)會在其他線程并行執(zhí)行戳护。請注意這里是并行執(zhí)行金抡。#1.創(chuàng)建一個其他隊列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; #2.創(chuàng)建NSBlockOperation對象 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"%@", [NSThread currentThread]); }]; #.添加多個Block for (NSInteger i = 0; i < 5; i++) { [operation addExecutionBlock:^{ NSLog(@"第%ld次:%@", i, [NSThread currentThread]); }]; } #.隊列添加任務(wù) [queue addOperation:operation];
NSOperationQueue的一些特殊使用
- 設(shè)置最大并發(fā)數(shù)
我們將 NSOperationQueue 與 GCD的隊列 相比較就會發(fā)現(xiàn),這里沒有串行隊列腌且,那如果我想要10個任務(wù)在其他線程串行的執(zhí)行的話梗肝,NSOperationQueue 有一個參數(shù) maxConcurrentOperationCount 最大并發(fā)數(shù),用來設(shè)置最多可以讓多少個任務(wù)同時執(zhí)行铺董。當你把它設(shè)置為 1 的時候巫击,就相當于是串行隊列了。
NSOperationQueue 添加一個任務(wù)到隊列
- (void)addOperationWithBlock:(void (^)(void))block; 這樣就可以添加一個任務(wù)到隊列中了精续。-
NSOperation 之間添加依賴
NSOperation 有一個非常實用的功能坝锰,那就是對任務(wù)添加依賴。比如有 3 個任務(wù):A: 從服務(wù)器上下載一張圖片重付,B:給這張圖片加個水印什黑,C:把圖片返回給服務(wù)器。這時就可以用到依賴了:
#1.任務(wù)一:下載圖片 NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"下載圖片 - %@", [NSThread currentThread]); [NSThread sleepForTimeInterval:1.0]; }]; #2.任務(wù)二:打水印 NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"打水印 - %@", [NSThread currentThread]); [NSThread sleepForTimeInterval:1.0]; }]; #3.任務(wù)三:上傳圖片 NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"上傳圖片 - %@", [NSThread currentThread]); [NSThread sleepForTimeInterval:1.0]; }]; #4.設(shè)置依賴 [operation2 addDependency:operation1]; //任務(wù)二依賴任務(wù)一 [operation3 addDependency:operation2]; //任務(wù)三依賴任務(wù)二 #5.創(chuàng)建隊列并加入任務(wù) NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];
注意
A.不能添加相互依賴堪夭,會死鎖愕把,比如 A依賴B,B依賴A森爽。
B.可以使用 removeDependency 來解除依賴關(guān)系恨豁。
C.可以在不同的隊列之間依賴,依賴是添加到任務(wù)身上的爬迟,和隊列沒關(guān)系橘蜜。 -
線程的掛起
#pragma mark - 線程的掛起 #暫停繼續(xù)(對隊列的暫停和繼續(xù)),掛起的是隊列付呕,不會影響已經(jīng)在執(zhí)行的操作 - (IBAction)pause:(UIButton *)sender { //判斷操作的數(shù)量计福,當前隊列里面是不是有操作? if (self.opQueue.operationCount == 0) { NSLog(@"當前隊列沒有操作"); return; } self.opQueue.suspended = !self.opQueue.isSuspended; if (self.opQueue.suspended) { NSLog(@"暫停"); }else{ NSLog(@"繼續(xù)"); }
}
-
取消隊列里的所有操作
#pragma mark - 取消隊列里的所有操作 - (IBAction)cancelAll:(UIButton *)sender { # 只能取消所有隊列的里面的操作徽职,正在執(zhí)行的無法取消 # 取消操作并不會影響隊列的掛起狀態(tài) [self.opQueue cancelAllOperations]; NSLog(@"取消隊列里所有的操作"); //取消隊列的掛起狀態(tài) #(只要是取消了隊列的操作象颖,我們就把隊列處于不掛起狀態(tài),以便于后續(xù)的開始) self.opQueue.suspended = NO; }
其他方法
以上就是一些主要方法, 下面還有一些常用方法需要大家注意:
# NSOperation
BOOL executing; //判斷任務(wù)是否正在執(zhí)行
BOOL finished; //判斷任務(wù)是否完成
#當一個 operation 被取消時,它的 completion block 仍然會執(zhí)行姆钉,
#所以我們需要在真正執(zhí)行代碼前檢查一下 isCancelled 方法的返回值说订。
- void (^completionBlock)(void); //用來設(shè)置完成后需要執(zhí)行的操作
- (void)cancel; //取消任務(wù)
- (void)waitUntilFinished; //阻塞當前線程直到此任務(wù)執(zhí)行完畢
# NSOperationQueue
NSUInteger operationCount; //獲取隊列的任務(wù)數(shù)
- (void)cancelAllOperations; //取消隊列中所有的任務(wù)
#阻塞當前線程直到此隊列中的所有任務(wù)執(zhí)行完畢
# **可以用來處理所有任務(wù)完成后的事件**
- (void)waitUntilAllOperationsAreFinished;
[queue setSuspended:YES]; // 暫停queue
[queue setSuspended:NO]; // 繼續(xù)queue
NSOperation和GCD的區(qū)別和類似的地方
- GCD是純C語言的API,NSOperationQueue是基于GCD的OC版本封裝
- GCD只支持FIFO的隊列潮瓶,NSOperationQueue可以很方便地調(diào)整執(zhí)行順序陶冷、設(shè)置最大并發(fā)數(shù)量
- NSOperationQueue可以在輕松在Operation間設(shè)置依賴關(guān)系,而GCD需要寫很多的代碼才能實現(xiàn)
- NSOperationQueue支持KVO毯辅,可以監(jiān)測operation是否正在執(zhí)行(isExecuted)埂伦、是否結(jié)束(isFinished),是否取消(isCanceld)
- GCD的執(zhí)行速度比NSOperationQueue快
**任務(wù)之間沒有什么依賴關(guān)系思恐,而是需要更高的并發(fā)能力:GCD **
任務(wù)之間有依賴沾谜、或者要監(jiān)聽任務(wù)的執(zhí)行情況膊毁、需要暫停、繼續(xù)任務(wù):NSOperationQueue
小結(jié)
以上就是關(guān)于 NSOperation和NSOperationQueue 的主要知識了类早,后期如果有更多內(nèi)容會同步更新媚媒。