NSOperationQueue

一、簡(jiǎn)介
一個(gè)NSOperation對(duì)象可以通過調(diào)用start方法來執(zhí)行任務(wù),默認(rèn)是同步執(zhí)行的。也可以將NSOperation添加到一個(gè)NSOperationQueue(操作隊(duì)列)中去執(zhí)行,而且是異步執(zhí)行的。
創(chuàng)建一個(gè)操作隊(duì)列:

NSOperationQueue *queue = [[NSOperationQueue alloc] init];  

二、添加NSOperation到NSOperationQueue中
1.添加一個(gè)operation

[queue addOperation:operation];  

2.添加一組operation

[queue addOperations:operations waitUntilFinished:NO];  

3.添加一個(gè)block形式的operation

[queue addOperationWithBlock:^() {  
    NSLog(@"執(zhí)行一個(gè)新的操作,線程:%@", [NSThread currentThread]);  
}];  

NSOperation添加到queue之后,通常短時(shí)間內(nèi)就會(huì)得到運(yùn)行。但是如果存在依賴,或者整個(gè)queue被暫停等原因,也可能需要等待。
注意:NSOperation添加到queue之后,絕對(duì)不要再修改NSOperation對(duì)象的狀態(tài)。因?yàn)镹SOperation對(duì)象可能會(huì)在任何時(shí)候運(yùn)行,因此改變NSOperation對(duì)象的依賴或數(shù)據(jù)會(huì)產(chǎn)生不利的影響。你只能查看NSOperation對(duì)象的狀態(tài), 比如是否正在運(yùn)行、等待運(yùn)行、已經(jīng)完成等

三、添加NSOperation的依賴對(duì)象
1.當(dāng)某個(gè)NSOperation對(duì)象依賴于其它NSOperation對(duì)象的完成時(shí),就可以通過addDependency方法添加一個(gè)或者多個(gè)依賴的對(duì)象,只有所有依賴的對(duì)象都已經(jīng)完成操作,當(dāng)前NSOperation對(duì)象才會(huì)開始執(zhí)行操作。另外,通過removeDependency方法來刪除依賴對(duì)象。

[operation2 addDependency:operation1];  

依賴關(guān)系不局限于相同queue中的NSOperation對(duì)象,NSOperation對(duì)象會(huì)管理自己的依賴, 因此完全可以在不同的queue之間的NSOperation對(duì)象創(chuàng)建依賴關(guān)系
唯一的限制是不能創(chuàng)建環(huán)形依賴,比如A依賴B,B依賴A,這是錯(cuò)誤的

2.依賴關(guān)系會(huì)影響到NSOperation對(duì)象在queue中的執(zhí)行順序,看下面的例子:
1> 沒有設(shè)置依賴關(guān)系

NSOperationQueue *queue = [[NSOperationQueue alloc] init];  
  
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){  
    NSLog(@"執(zhí)行第1次操作,線程:%@", [NSThread currentThread]);  
}];  
  
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){  
    NSLog(@"執(zhí)行第2次操作,線程:%@", [NSThread currentThread]);  
}];  
  
[queue addOperation:operation1];  
[queue addOperation:operation2];  

打印信息:

2013-02-03 00:21:35.024 thread[5616:3d13] 執(zhí)行第1次操作,線程:<NSThread: 0x7658570>{name = (null), num = 3}  
2013-02-03 00:21:35.063 thread[5616:1303] 執(zhí)行第2次操作,線程:<NSThread: 0x765a2e0>{name = (null), num = 4}  

可以看出,默認(rèn)是按照添加順序執(zhí)行的,先執(zhí)行operation1,再執(zhí)行operation2

2> 設(shè)置了依賴關(guān)系

NSOperationQueue *queue = [[NSOperationQueue alloc] init];  
  
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){  
    NSLog(@"執(zhí)行第1次操作,線程:%@", [NSThread currentThread]);  
}];  
  
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){  
    NSLog(@"執(zhí)行第2次操作,線程:%@", [NSThread currentThread]);  
}];  
// operation1依賴于operation2  
[operation1 addDependency:operation2];  
  
[queue addOperation:operation1];  
[queue addOperation:operation2];  

打印信息:

2013-02-03 00:24:16.260 thread[5656:1b03] 執(zhí)行第2次操作,線程:<NSThread: 0x7634490>{name = (null), num = 3}  
2013-02-03 00:24:16.285 thread[5656:1303] 執(zhí)行第1次操作,線程:<NSThread: 0x9138b50>{name = (null), num = 4}  

可以看出,先執(zhí)行operation2,再執(zhí)行operation1

四、修改Operations的執(zhí)行順序
對(duì)于添加到queue中的operations,它們的執(zhí)行順序取決于2點(diǎn):
1.首先看看NSOperation是否已經(jīng)準(zhǔn)備好:是否準(zhǔn)備好由對(duì)象的依賴關(guān)系確定
2.然后再根據(jù)所有NSOperation的相對(duì)優(yōu)先級(jí)來確定。優(yōu)先級(jí)等級(jí)則是operation對(duì)象本身的一個(gè)屬性。默認(rèn)所有operation都擁有“普通”優(yōu)先級(jí),不過可以通過setQueuePriority:方法來提升或降低operation對(duì)象的優(yōu)先級(jí)。優(yōu)先級(jí)只能應(yīng)用于相同queue中的operations。如果應(yīng)用有多個(gè)operation queue,每個(gè)queue的優(yōu)先級(jí)等級(jí)是互相獨(dú)立的。因此不同queue中的低優(yōu)先級(jí)操作仍然可能比高優(yōu)先級(jí)操作更早執(zhí)行。
注意:優(yōu)先級(jí)不能替代依賴關(guān)系,優(yōu)先級(jí)只是對(duì)已經(jīng)準(zhǔn)備好的 operations確定執(zhí)行順序。先滿足依賴關(guān)系,然后再根據(jù)優(yōu)先級(jí)從所有準(zhǔn)備好的操作中選擇優(yōu)先級(jí)最高的那個(gè)執(zhí)行。

五、設(shè)置隊(duì)列的最大并發(fā)操作數(shù)量
隊(duì)列的最大并發(fā)操作數(shù)量,意思是隊(duì)列中最多同時(shí)運(yùn)行幾條線程
雖然NSOperationQueue類設(shè)計(jì)用于并發(fā)執(zhí)行Operations,你也可以強(qiáng)制單個(gè)queue一次只能執(zhí)行一個(gè)Operation。setMaxConcurrentOperationCount:方法可以配置queue的最大并發(fā)操作數(shù)量。設(shè)為1就表示queue每次只能執(zhí)行一個(gè)操作。不過operation執(zhí)行的順序仍然依賴于其它因素,比如operation是否準(zhǔn)備好和operation的優(yōu)先級(jí)等。因此串行化的operation queue并不等同于GCD中的串行dispatch queue

// 每次只能執(zhí)行一個(gè)操作  
queue.maxConcurrentOperationCount = 1;  
// 或者這樣寫  
[queue setMaxConcurrentOperationCount:1];  

六、取消Operations
一旦添加到operation queue,queue就擁有了這個(gè)Operation對(duì)象并且不能被刪除,唯一能做的事情是取消。你可以調(diào)用Operation對(duì)象的cancel方法取消單個(gè)操作,也可以調(diào)用operation queue的cancelAllOperations方法取消當(dāng)前queue中的所有操作。

// 取消單個(gè)操作  
[operation cancel];  
  
// 取消queue中所有的操作  
[queue cancelAllOperations];  

七、等待Options完成
為了最佳的性能,你應(yīng)該設(shè)計(jì)你的應(yīng)用盡可能地異步操作,讓應(yīng)用在Operation正在執(zhí)行時(shí)可以去處理其它事情。如果需要在當(dāng)前線程中處理operation完成后的結(jié)果,可以使用NSOperation的waitUntilFinished方法阻塞當(dāng)前線程,等待operation完成。通常我們應(yīng)該避免編寫這樣的代碼,阻塞當(dāng)前線程可能是一種簡(jiǎn)便的解決方案,但是它引入了更多的串行代碼,限制了整個(gè)應(yīng)用的并發(fā)性,同時(shí)也降低了用戶體驗(yàn)。絕對(duì)不要在應(yīng)用主線程中等待一個(gè)Operation,只能在第二或次要線程中等待。阻塞主線程將導(dǎo)致應(yīng)用無法響應(yīng)用戶事件,應(yīng)用也將表現(xiàn)為無響應(yīng)。

// 會(huì)阻塞當(dāng)前線程,等到某個(gè)operation執(zhí)行完畢  
[operation waitUntilFinished];  

除了等待單個(gè)Operation完成,你也可以同時(shí)等待一個(gè)queue中的所有操作,使用NSOperationQueue的waitUntilAllOperationsAreFinished方法。注意:在等待一個(gè) queue時(shí),應(yīng)用的其它線程仍然可以往queue中添加Operation,因此可能會(huì)加長線程的等待時(shí)間。

// 阻塞當(dāng)前線程,等待queue的所有操作執(zhí)行完畢  
[queue waitUntilAllOperationsAreFinished];  

八、暫停和繼續(xù)queue
如果你想臨時(shí)暫停Operations的執(zhí)行,可以使用queue的setSuspended:方法暫停queue。不過暫停一個(gè)queue不會(huì)導(dǎo)致正在執(zhí)行的operation在任務(wù)中途暫停,只是簡(jiǎn)單地阻止調(diào)度新Operation執(zhí)行。你可以在響應(yīng)用戶請(qǐng)求時(shí),暫停一個(gè)queue來暫停等待中的任務(wù)。稍后根據(jù)用戶的請(qǐng)求,可以再次調(diào)用setSuspended:方法繼續(xù)queue中operation的執(zhí)行

// 暫停queue  
[queue setSuspended:YES];  
  
// 繼續(xù)queue  
[queue setSuspended:NO];  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容