iOS編程中,有多種并發(fā)編程的方式膛腐,比較常見的就是基于Operation Queue和GCD睛约,還有底層一點的NSTheard,本文主要討論Operation Queue和GCD
異步調(diào)用和并發(fā)
在談并發(fā)之前哲身,談一談異步調(diào)用和并發(fā)辩涝,異步調(diào)用是指調(diào)用時無需等待結(jié)果返回的調(diào)用。并發(fā)是指多個任務(wù)(線程)同時執(zhí)行勘天,在異步調(diào)用的實現(xiàn)中往往用的都是并發(fā)機制怔揩,但也有可能是其他機制,比如一些依靠中斷進行的操作脯丝。(中斷:(Interrupt)是指處理器接收到來自硬件或軟件的信號商膊,提示發(fā)生了某個事件,應(yīng)該被注意宠进,這種情況就稱為中斷晕拆。)
Operation Queue
operation queue提供了一個面向?qū)ο蟮牟l(fā)編程接口,并支持并發(fā)數(shù)(僅operation queue支持)材蹬,線程優(yōu)先級实幕,任務(wù)優(yōu)先級,任務(wù)依賴關(guān)系等多種配置
1.面向?qū)ο蠼涌?br>
2.支持并發(fā)數(shù)配置
3.任務(wù)優(yōu)先級調(diào)度
4.任務(wù)依賴關(guān)系
5.線程優(yōu)先級配置
NSOperation簡介
在operation queue中堤器,把每個并發(fā)任務(wù)都定義為一個operation昆庇,對應(yīng)的類名是NSOperation,NSOperation是一個抽象類吼旧,無法直接使用凰锡,它只定義了Operation的一些基本方法,我們需要創(chuàng)建一個基于他的子類或者使用系統(tǒng)預(yù)定于的子類圈暗,目前系統(tǒng)預(yù)定義了兩個子類:NSInvocationOperation和NSBlockOperation掂为。
NSInvocationOperation
NSInvocationOperation是一個基于對象和selector的Operation,使用這個你只需要指定對象以及任務(wù)的selector员串,如果有必要勇哗,還可以設(shè)定傳遞的參數(shù)。
NSInvocationOperation *invacationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomethingWithObj:) object:obj];
當(dāng)這個Operation完成后寸齐,你可以通過下面的方法獲得調(diào)用執(zhí)行后返回的結(jié)果對象欲诺。
id result = [invacationOperation result];
NSBlockOperation
如果不是在一個函數(shù)中執(zhí)行任務(wù)抄谐,而是在一個block中執(zhí)行一個任務(wù)的話,這是我們就需要NSBlockOperation
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
//Do?something?here.
}];
運行一個Operation
[Operation start] 扰法;
start方法用來啟動一個Operation任務(wù)蛹含。同時,Operation提供一個main方法塞颁,你的所有任務(wù)都應(yīng)該在main中進行處理浦箱。默認(rèn)的start方法中會先做出一些異常判斷然后直接調(diào)用main方法。如果需要自定義一個NSOperation必須重載main方法來執(zhí)行你所想要執(zhí)行的任務(wù)祠锣。
取消一個Operation
要取消一個Operation酷窥,要發(fā)送cancel消息:
[operation cancel];
當(dāng)像一個Operation對象發(fā)送cancel消息之后,并不能保證這個Operation就一定能理科取消伴网,這取決于你的main中對cancel的處理蓬推,,如果你在main中沒有對cancel進行任何處理的話澡腾,發(fā)送cancel消息是沒有任何效果的沸伏,為了讓Operation響應(yīng)cancel消息,那么你就要在main方法中一些適當(dāng)?shù)牡胤绞謩优袛鄆sCancelled屬性蛋铆,如果返回為YES的話馋评,應(yīng)該釋放相關(guān)資源并立刻停止繼續(xù)執(zhí)行。
創(chuàng)建可并發(fā)的Operation
由于默認(rèn)下Operation的start方法中直接調(diào)用了main方法刺啦,而main方法中會有比較耗時的處理任務(wù)留特,如果我們在一段代碼中連續(xù)start了多個Operation的話,這個Operation都是阻塞地依次執(zhí)行完玛瘸,因為第二個Operation必須等到第一個Operation執(zhí)行完start內(nèi)的main并返回蜕青,Operation默認(rèn)都是不可并發(fā)的(使用了Operation Queue除外,Operation Queue會獨自管理自己的線程)糊渊,因為默認(rèn)Operation并不額外創(chuàng)建賢臣右核,我們可以通過OPeration的isConcurrent方法來判斷Operation是否是可并發(fā)的,如果要讓OPeration可并發(fā)渺绒,我們需要讓main在單獨的線程執(zhí)行贺喝,并將isConcurrent返回YES。
這個方法是在每一個Operation中自己用NSThread來創(chuàng)建線程宗兼,當(dāng)然躏鱼,這樣的行為并不是如我們所愿的
@implementation MyOperation{
BOOL????????executing;
BOOL????????finished;
}
-?(BOOL)isConcurrent?{
returnYES;
}
-?(void)start?{
if([self?isCancelled])
{
[self?willChangeValueForKey:@"isFinished"];
finished?=?YES;
[self?didChangeValueForKey:@"isFinished"];
return;
}
[self?willChangeValueForKey:@"isExecuting"];
[NSThread?detachNewThreadSelector:@selector(main)?toTarget:self?withObject:nil];
executing?=?YES;
[self?didChangeValueForKey:@"isExecuting"];
}
-?(void)main?{
@try{
//?Do?some?work.
[self?willChangeValueForKey:@"isFinished"];
[self?willChangeValueForKey:@"isExecuting"];
executing?=?NO;
finished?=?YES;
[self?didChangeValueForKey:@"isExecuting"];
[self?didChangeValueForKey:@"isFinished"];
}
@catch(...)?{
//?Exception?handle.
}
}
@end
當(dāng)你自定義了start或main方法時,一定要手動的調(diào)用一些KVO通知方法殷绍,以便讓對象的KVO機制可以正常運作染苛。