Mac OS X 10.6及iOS4.0之后導(dǎo)入了可以使全體線程更高效運行幅慌,并且使并行處理應(yīng)用更易開發(fā)的架構(gòu)辫秧,GCD(Grand Central? Dispatch)担锤,同時引入的還有Run Loop,線程(包括Cocoa和POSIX)和Operation儿礼。GCD擁有非常輕量級的工作單元和并發(fā)方式咖杂,并且由系統(tǒng)決定其最佳調(diào)度方式。這個時候出現(xiàn)了一個問題蚊夫,NSOperation如何處理呢诉字?
其實我們在通過NSOperation和GCD進行開發(fā)過程中,會發(fā)現(xiàn)兩者執(zhí)行的方式有許多相似之處知纷,NSOperation和GCD參照對比壤圃,NSOperationQueue和dispatch_queue參照對比,但是兩者之間還是有許多差別的琅轧,具體區(qū)別:
1.GCD的核心是C語言寫的系統(tǒng)服務(wù)伍绳,執(zhí)行和操作簡單高效,因此NSOperation底層也通過GCD實現(xiàn)乍桂,換個說法就是NSOperation是對GCD更高層次的抽象冲杀,這是他們之間最本質(zhì)的區(qū)別.因此如果希望自定義任務(wù)效床,建議使用NSOperation;
2.依賴關(guān)系权谁,NSOperation可以設(shè)置兩個NSOperation之間的依賴剩檀,第二個任務(wù)依賴于第一個任務(wù)完成執(zhí)行,GCD無法設(shè)置依賴關(guān)系旺芽,不過可以通過dispatch_barrier_async來實現(xiàn)這種效果谨朝;
3.KVO(鍵值對觀察),NSOperation和容易判斷Operation當前的狀態(tài)(是否執(zhí)行甥绿,是否取消),對此GCD無法通過KVO進行判斷则披;
4.優(yōu)先級共缕,NSOperation可以設(shè)置自身的優(yōu)先級士复,但是優(yōu)先級高的不一定先執(zhí)行图谷,GCD只能設(shè)置隊列的優(yōu)先級,無法在執(zhí)行的block設(shè)置優(yōu)先級阱洪;
5.繼承便贵,NSOperation是一個抽象類實際開發(fā)中常用的兩個類是NSInvocationOperation和NSBlockOperation,同樣我們可以自定義NSOperation冗荸,GCD執(zhí)行任務(wù)可以自由組裝承璃,沒有繼承那么高的代碼復(fù)用度;
6.效率蚌本,直接使用GCD效率確實會更高效盔粹,NSOperation會多一點開銷,但是通過NSOperation可以獲得依賴程癌,優(yōu)先級舷嗡,繼承,鍵值對觀察這些優(yōu)勢嵌莉,相對于多的那么一點開銷確實很劃算进萄,魚和熊掌不可得兼,取舍在于開發(fā)者自己锐峭;
關(guān)于主要的區(qū)別都已經(jīng)總結(jié)中鼠,根據(jù)實際開發(fā)中來說,GCD使用情況較多只祠,簡單高效兜蠕,從變成原則上來看,應(yīng)該是使用高層次的抽象抛寝,避免使用低層次的抽象熊杨,那么無疑我們應(yīng)該選擇NSOperation曙旭,因為復(fù)雜的任務(wù)可以自己通過NSOperation實現(xiàn),日常還是GCD的天下晶府,畢竟GCD有更高的并發(fā)和執(zhí)行能力
NSOperation是蘋果封裝的一套多線程的東西桂躏,不像GCD是純C語言的,這個是OC的川陆。但相比較之下GCD會更快一些剂习,但本質(zhì)上NSOPeration是多GDC的封裝。
一较沪、NSOperation與GCD的比較
GCD是基于c的底層api鳞绕,NSOperation屬于object-c類。ios首先引入的是NSOperation尸曼,IOS4之后引入了GCD和NSOperationQueue并且其內(nèi)部是用gcd實現(xiàn)的们何。
GCD優(yōu)點:GCD主要與block結(jié)合使用。代碼簡潔高效控轿。執(zhí)行效率稍微高點冤竹。
NSOperation相對于GCD:
1,NSOperation擁有更多的函數(shù)可用茬射,具體查看api鹦蠕。NSOperationQueue 是在GCD基礎(chǔ)上實現(xiàn)的,只不過是GCD更高一層的抽象在抛。
2钟病,在NSOperationQueue中,可以建立各個NSOperation之間的依賴關(guān)系霜定。
3档悠,NSOperationQueue支持KVO⊥疲可以監(jiān)測operation是否正在執(zhí)行(isExecuted)辖所、是否結(jié)束(isFinished),是否取消(isCanceld)
4磨德,GCD 只支持FIFO 的隊列缘回,而NSOperationQueue可以調(diào)整隊列的執(zhí)行順序(通過調(diào)整權(quán)重)。NSOperationQueue可以方便的管理并發(fā)典挑、NSOperation之間的優(yōu)先級酥宴。
使用NSOperation的情況:各個操作之間有依賴關(guān)系、操作需要取消暫停您觉、并發(fā)管理拙寡、控制操作之間優(yōu)先級,限制同時能執(zhí)行的線程數(shù)量.讓線程在某時刻停止/繼續(xù)等琳水。
使用GCD的情況:一般的需求很簡單的多線程操作肆糕,用GCD都可以了般堆,簡單高效。
從編程原則來說诚啃,一般我們需要盡可能的使用高等級淮摔、封裝完美的API,在必須時才使用底層API始赎。
當需求簡單和橙,簡潔的GCD或許是個更好的選擇,而Operation queue 為我們提供能更多的選擇造垛。
二魔招、NSOperation的簡單操作
?NSOperation(操作)配NSoperationQueue(隊列)來實現(xiàn)多線程.
?沒有像GCD一樣串行并行什么的,直接拿來就能用.
?操作依賴:NSOperation可以通過設(shè)置依賴來保證執(zhí)行順序.某一個操作的執(zhí)行, 必須等待另一個操作完成才會繼續(xù)執(zhí)行.
使用:[op1addDependency:op2] ?依賴關(guān)系可以跨隊列指定的.(不能弄成循環(huán)依賴)
?可以指定隊列的優(yōu)先級。
使用NSOperation的方法(3者是等價的):(注意NSOperation是抽象類,
必須使用他的子類才能實現(xiàn))
?方法1五辽、用NSOperation的子類NSInvocationOperation來創(chuàng)建操作.
?方法2仆百、用NSOperation的子類NSBlockOperation來創(chuàng)建操作.?(與前者效果一樣)
?方法3、直接弄個隊列(可以是主隊列,先跑起來),再addOperationWithBlock更加簡便.
?方法4奔脐、直接自定義NSOperation,實現(xiàn)相應(yīng)的方法吁讨。
實現(xiàn)NSOperation的方法髓迎,以及掛起、暫停建丧,設(shè)置最大并發(fā)數(shù)排龄,設(shè)置依賴關(guān)系等。
[objc]view
plaincopy
@interfaceXNViewController?()
/**?NSOperation操作隊列?*/
@property(nonatomic,strong)NSOperationQueue*queue;
@end
@implementationXNViewController
//?將操作添加到隊列即可
-?(NSOperationQueue*)queue
{
if(!_queue)?_queue?=?[[NSOperationQueuealloc]init];
return_queue;
}
/**?=============================?暫停掛起?=============================?*/
/**?暫停操作?*/
-?(IBAction)pause
{
//?1.?判斷隊列中是否有操作
if(self.queue.operationCount==0)?{
NSLog(@"沒有操作");
return;
}
//?2.?如果沒有被掛起(正在執(zhí)行)翎朱,才需要暫停
//?只會掛起當前隊列中還沒有被調(diào)度(沒有被安排到線程上工作的操作)才會被掛起
if(!self.queue.isSuspended)?{
NSLog(@"暫停");
[self.queuesetSuspended:YES];
}else{
NSLog(@"已經(jīng)暫停");
}
}
/**?繼續(xù)操作?*/
-?(IBAction)resume
{
//?1.?判斷隊列中是否有操作
if(self.queue.operationCount==0)?{
NSLog(@"沒有操作");
return;
}
//?2.?如果有被掛起的操作橄维,才需要繼續(xù)(恢復(fù))
if(self.queue.isSuspended)?{
NSLog(@"繼續(xù)");
[self.queuesetSuspended:NO];
}else{
NSLog(@"正在執(zhí)行");
}
}
/**?========================NSOperation指定操作之間的依賴關(guān)系========================*/
-?(void)opDemo6
{
NSBlockOperation*op1=?[NSBlockOperationblockOperationWithBlock:^{
NSLog(@"正在下載蒼老師全集?。拴曲。争舞。?%@",?[NSThreadcurrentThread]);
}];
NSBlockOperation*op2=?[NSBlockOperationblockOperationWithBlock:^{
NSLog(@"正在解壓縮蒼老師全集。澈灼。竞川。?%@",?[NSThreadcurrentThread]);
}];
NSBlockOperation*op3=?[NSBlockOperationblockOperationWithBlock:^{
NSLog(@"正在保存到磁盤?。叁熔。委乌。?%@",?[NSThreadcurrentThread]);
}];
NSBlockOperation*op4=?[NSBlockOperationblockOperationWithBlock:^{
NSLog(@"下載完成?。?%@",?[NSThreadcurrentThread]);
}];
//?指定操作之間的”依賴“關(guān)系荣回,某一個操作的執(zhí)行遭贸,必須等待另一個操作完成才會開始
//?依賴關(guān)系是可以跨隊列指定的
[op2addDependency:op1];
[op3addDependency:op2];
[op4addDependency:op3];
//?***?添加依賴的時候,注意不要出現(xiàn)循環(huán)依賴
//????[op3?addDependency:op4];
[self.queueaddOperation:op1];
[self.queueaddOperation:op2];
[self.queueaddOperation:op3];
//?主隊列更新UI
[[NSOperationQueuemainQueue]addOperation:op4];
}
/**?==================================設(shè)置最大并發(fā)數(shù)====================================?*/
-?(void)opDemo5
{
//?設(shè)置隊列的最大并發(fā)數(shù)心软,隊列是負責調(diào)度操作的
/**
最大并發(fā)數(shù)的應(yīng)用場景:
1>?用戶在使用3G的時候??????????限制線程的數(shù)量壕吹,省電著蛙,省流量(省錢)
2>?用戶使用WIFI的時候(局域網(wǎng))?增加線程數(shù)量,提高用戶的體驗
maxConcurrentOperationCount?如果==?1算利,類似于串行隊列異步方法
*/
self.queue.maxConcurrentOperationCount=1;
for(inti?=0;?i?<10;?i++)?{
[self.queueaddOperationWithBlock:^{
NSLog(@"正在下載?%@?%d",?[NSThreadcurrentThread],?i);
}];
}
}
/**??=============================?Block操作册踩,添加執(zhí)行塊?=============================??*/
-?(void)opDemo4
{
//?實例化block操作
NSBlockOperation*op?=?[[NSBlockOperationalloc]init];
//?設(shè)置最大并發(fā)(操作)數(shù),不會限制執(zhí)行塊效拭!
self.queue.maxConcurrentOperationCount=2;
//?添加執(zhí)行塊
[opaddExecutionBlock:^{
NSLog(@"下載蒼老師全集1?%@",?[NSThreadcurrentThread]);
}];
//?繼續(xù)添加塊
[opaddExecutionBlock:^{
NSLog(@"下載蒼老師全集2?%@",?[NSThreadcurrentThread]);
}];
//?繼續(xù)添加塊
[opaddExecutionBlock:^{
NSLog(@"下載蒼老師全集3?%@",?[NSThreadcurrentThread]);
}];
//?繼續(xù)添加塊
[opaddExecutionBlock:^{
NSLog(@"下載蒼老師全集4?%@",?[NSThreadcurrentThread]);
}];
//?繼續(xù)添加塊
[opaddExecutionBlock:^{
NSLog(@"下載蒼老師全集5?%@",?[NSThreadcurrentThread]);
}];
//?啟動操作暂吉,在主線程執(zhí)行
//?如果執(zhí)行塊的數(shù)量超過1,就會自動進入其他線程執(zhí)行(異步)
//?具體開啟線程的數(shù)量缎患,由系統(tǒng)決定
//?執(zhí)行塊的調(diào)度與操作的調(diào)度非常像
//????[op?start];
[self.queueaddOperation:op];
}
/**?=============================?直接添加塊操作?=============================?*/
-?(void)opDemo3
{
//?只要將操作添加到隊列就會立即被調(diào)度(執(zhí)行)
for(inti?=0;?i?<10;?i++)?{
[self.queueaddOperationWithBlock:^{
NSLog(@"下載開始?%@?-?%@",?[NSThreadcurrentThread],?@(i));
}];
}
//?向主隊列中添加操作
[[NSOperationQueuemainQueue]addOperationWithBlock:^{
NSLog(@"下載開始?%@?-?%@",?[NSThreadcurrentThread],nil);
}];
}
/**=============================?NSBlockOperation?=============================*/
-?(void)opDemo2
{
for(inti?=0;?i?<10;?i++)?{
//?指定一個塊操作
NSBlockOperation*op1=?[NSBlockOperationblockOperationWithBlock:^{
NSLog(@"下載開始?%@?-?%@",?[NSThreadcurrentThread],?@(i));
}];
//?將塊操作添加到隊列.?新開線程
[self.queueaddOperation:op1];
}
}
/**?=============================NSInvocationOperation=============================?*/
-?(void)opDemo1
{
for(inti?=0;?i?<10;?i++)?{
NSInvocationOperation*op1=?[[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(download:)object:@(i)];
//?如果直接啟動慕的,會在主線程執(zhí)行
//????[op1?start];
//?添加到隊列,就會新建線程挤渔,異步執(zhí)行
[self.queueaddOperation:op1];
}
}
-?(void)download:(id)obj
{
NSLog(@"下載開始?%@?-?%@",?[NSThreadcurrentThread],?obj);
}
@end
自定義NSOperation:
1肮街、繼承NSOperation
2、重新main方法
[objc]view
plaincopy
@interfaceXNMyOperation?:?NSOperation
@end
//============================上為.h頭文件判导,下為.m文件=============================
@implementationXNMyOperation
//?只要重寫main就可以了
-?(void)main
{
//?自定義操作嫉父,一定要自己添加自動釋放池
@autoreleasepool{
//。眼刃。绕辖。。擂红。仪际。。昵骤。树碱。。变秦。
}
}
@end