一凯砍、簡(jiǎn)介
一個(gè)NSOperation對(duì)象可以通過(guò)調(diào)用start方法來(lái)執(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í)赦役,就可以通過(guò)addDependency方法添加一個(gè)或者多個(gè)依賴的對(duì)象,只有所有依賴的對(duì)象都已經(jīng)完成操作栅炒,當(dāng)前NSOperation對(duì)象才會(huì)開始執(zhí)行操作掂摔。另外,通過(guò)removeDependency方法來(lái)刪除依賴對(duì)象赢赊。
[java]view plaincopy
[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)系
[java]view plaincopy
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];
打印信息:
[java]view plaincopy
2013-02-0300:21:35.024thread[5616:3d13]?執(zhí)行第1次操作趋观,線程:{name?=?(null),?num?=3}
2013-02-0300:21:35.063thread[5616:1303]?執(zhí)行第2次操作,線程:{name?=?(null),?num?=4}
可以看出锋边,默認(rèn)是按照添加順序執(zhí)行的皱坛,先執(zhí)行operation1,再執(zhí)行operation2
2> 設(shè)置了依賴關(guān)系
[java]view plaincopy
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];
打印信息:
[java]view plaincopy
2013-02-0300:24:16.260thread[5656:1b03]?執(zhí)行第2次操作,線程:{name?=?(null),?num?=3}
2013-02-0300:24:16.285thread[5656:1303]?執(zhí)行第1次操作往扔,線程:{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í)來(lái)確定葛假。優(yōu)先級(jí)等級(jí)則是operation對(duì)象本身的一個(gè)屬性丽涩。默認(rèn)所有operation都擁有“普通”優(yōu)先級(jí),不過(guò)可以通過(guò)setQueuePriority:方法來(lái)提升或降低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è)操作桃移。不過(guò)operation執(zhí)行的順序仍然依賴于其它因素,比如operation是否準(zhǔn)備好和operation的優(yōu)先級(jí)等。因此串行化的operation queue并不等同于GCD中的串行dispatch queue
[java]view plaincopy
//?每次只能執(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中的所有操作过吻。
[java]view plaincopy
//?取消單個(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)用無(wú)法響應(yīng)用戶事件,應(yīng)用也將表現(xiàn)為無(wú)響應(yīng)洋措。
[java]view plaincopy
//?會(huì)阻塞當(dāng)前線程,等到某個(gè)operation執(zhí)行完畢
[operation?waitUntilFinished];
除了等待單個(gè)Operation完成,你也可以同時(shí)等待一個(gè)queue中的所有操作,使用NSOperationQueue的waitUntilAllOperationsAreFinished方法杰刽。注意:在等待一個(gè) queue時(shí),應(yīng)用的其它線程仍然可以往queue中添加Operation,因此可能會(huì)加長(zhǎng)線程的等待時(shí)間菠发。
[java]view plaincopy
//?阻塞當(dāng)前線程,等待queue的所有操作執(zhí)行完畢
[queue?waitUntilAllOperationsAreFinished];
八贺嫂、暫停和繼續(xù)queue
如果你想臨時(shí)暫停Operations的執(zhí)行,可以使用queue的setSuspended:方法暫停queue滓鸠。不過(guò)暫停一個(gè)queue不會(huì)導(dǎo)致正在執(zhí)行的operation在任務(wù)中途暫停,只是簡(jiǎn)單地阻止調(diào)度新Operation執(zhí)行。你可以在響應(yīng)用戶請(qǐng)求時(shí),暫停一個(gè)queue來(lái)暫停等待中的任務(wù)第喳。稍后根據(jù)用戶的請(qǐng)求,可以再次調(diào)用setSuspended:方法繼續(xù)queue中operation的執(zhí)行
[java]view plaincopy
//?暫停queue
[queue?setSuspended:YES];
//?繼續(xù)queue
[queue?setSuspended:NO];