iOS NSOperation學習及總結(jié)

這篇文章對iOS多線程技術(shù)NSOperation的常用方法做了簡單總結(jié)
GCD請見這篇
本文代碼

NSOperation:

- 簡介:

  • 是蘋果在GCD的基礎(chǔ)上做了一次面向?qū)ο蟮姆庋b
  • 核心概念和GCD很像
  • NSOperation是一個抽象類,想要封裝操作,需要使用子類
  • 可以自定義子類,繼承NSOperation,實現(xiàn)多線程操作

- NSOperation的子類:

  • NSInvocationOperation:
    NSInvocationOperation *op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];
    [op start];

打印結(jié)果:

------<NSThread: 0x600000260ac0>{number = 1, name = main}

結(jié)論:
如果僅僅是封裝了操作,然后調(diào)用start方法
他是不會開線程的
就像調(diào)用了performSelectorr一樣
想要開線程,必須把任務加到隊列中去
因為NSOperation底層是GCD,GCD就是把任務加入到隊列,根據(jù)隊列和函數(shù)的情況來決定是否開啟線程

  • NSBlockOperation:
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下載1------%@", [NSThread currentThread]);
    }];
    //添加額外任務
    [op addExecutionBlock:^{
        NSLog(@"下載2------%@", [NSThread currentThread]);
    }];
    [op addExecutionBlock:^{
        NSLog(@"下載3------%@", [NSThread currentThread]);
    }];
    [op start];

打印結(jié)果:

下載1------<NSThread: 0x60800006f180>{number = 1, name = main}
下載2------<NSThread: 0x6000000791c0>{number = 3, name = (null)}
下載3------<NSThread: 0x608000079e00>{number = 4, name = (null)}

結(jié)論:
和NSInvocationOperation一樣
如果只是封裝了操作并調(diào)用了start方法
只是會在主線程執(zhí)行任務
但是如果通過addExecutionBlock添加了新任務
那么新任務會在子線程執(zhí)行(這里是比較特殊的地方)

- NSOperationQueue:

NSOperation可以用start方法來執(zhí)行任務,但是默認是同步的
如果將NSOperation添加到NSOperationQueue中,系統(tǒng)會自動異步執(zhí)行NSOperation中的操作

    //創(chuàng)建隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    
    //創(chuàng)建操作(NSInvocationOperation)
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download1) object:nil];
    NSInvocationOperation *op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download2) object:nil];
    
    //創(chuàng)建操作(NSBlockOperation)
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download3 --- %@", [NSThread currentThread]);
    }];
    [op3 addExecutionBlock:^{
        NSLog(@"download4 --- %@", [NSThread currentThread]);
    }];
    [op3 addExecutionBlock:^{
        NSLog(@"download5 --- %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download6 --- %@", [NSThread currentThread]);
    }];
    
    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:op3];
    [queue addOperation:op4];

打印結(jié)果:

download6 --- <NSThread: 0x608000269080>{number = 6, name = (null)}
download2 --- <NSThread: 0x600000265240>{number = 4, name = (null)}
download1 --- <NSThread: 0x600000265200>{number = 3, name = (null)}
download3 --- <NSThread: 0x6000002655c0>{number = 5, name = (null)}
download4 --- <NSThread: 0x608000265f80>{number = 7, name = (null)}
download5 --- <NSThread: 0x600000265300>{number = 8, name = (null)}

結(jié)論:
NSOperation有兩種隊列:

  • 主隊列:
[NSOperationQueue mainQueue];

凡是添加到主隊列中的任務,都會在主線程執(zhí)行

  • 非主隊列
[[NSOperationQueue alloc]init];

同時包含了串行和并發(fā)的功能
就像上面的代碼,把任務添加到隊列以后,自動在子線程中執(zhí)行
如果想用非主線程實現(xiàn)串行,則需要設置并發(fā)量

- 其他用法:

  • 最大并發(fā)數(shù):
// 設置最大并發(fā)操作數(shù)
    queue.maxConcurrentOperationCount = 2;

設置了最大并發(fā)數(shù),就是限制了系統(tǒng)開線程的數(shù)量
如果設置為1
任務就會串行執(zhí)行

  • 掛起:
self.queue.suspended = YES;

當隊列中的任務正在執(zhí)行的時候,設置掛起為YES
任務會暫停
但是沒有從內(nèi)存中銷毀
當設置為NO的時候,任務會繼續(xù)進行

  • 取消所有任務:
[self.queue cancelAllOperations];

調(diào)用queue的cancelAllOperations方法
相當于調(diào)用了queue中每個NSOperation的cancel方法
所有的任務就被取消了
如果想繼續(xù)任務
需要重新定制任務加入隊列
但是需要注意的是:
如果調(diào)用cancel方法的時候,NSOperation有一個任務正在執(zhí)行
那么需要這個任務執(zhí)行完了以后,再實現(xiàn)cancel

  • 自定義NSOperation:

繼承NSOperation類
可以實現(xiàn)自定義NSOperation
需要執(zhí)行的任務在main方法中實現(xiàn)

#import "HXOperation.h"
@implementation HXOperation
/**
 * 需要執(zhí)行的任務
 */
-(void)main
{
    for (NSInteger i = 0; i<1000; i++) {
        NSLog(@"download1 -%zd-- %@", i, [NSThread currentThread]);
    }
    if (self.isCancelled) return;
    for (NSInteger i = 0; i<1000; i++) {
        NSLog(@"download2 -%zd-- %@", i, [NSThread currentThread]);
    }
    if (self.isCancelled) return;
    for (NSInteger i = 0; i<1000; i++) {
        NSLog(@"download3 -%zd-- %@", i, [NSThread currentThread]);
    }
    if (self.isCancelled) return;
}
@end

在外部這么使用就可以:

    // 創(chuàng)建隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    //添加NSOperation
    [queue addOperation:[[HXOperation alloc] init]];

這樣就會自動執(zhí)行main中的任務了
但是蘋果建議我們自定義NSOperation的時候,如果內(nèi)部有耗時操作
那么應該在每一個耗時操作結(jié)束以后,檢查一下當前任務有沒有被取消
因為很有可能NSOperation在執(zhí)行任務的時候,外部調(diào)用了他的cancel方法
如果被取消了就不要再執(zhí)行剩下的任務了:

if (self.isCancelled) return;
  • 任務依賴和任務監(jiān)聽

我們知道把多個任務加入隊列后
系統(tǒng)從隊列中把任務取出來并發(fā)執(zhí)行
但是誰先執(zhí)行取決于CPU先調(diào)度那條線程
當我們需要執(zhí)行某個任務之后再執(zhí)行其他任務的話(比如下載完圖片后再對圖片進行處理)
那么就需要設置依賴
或者可以對任務做監(jiān)聽

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download1----%@", [NSThread  currentThread]);
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download2----%@", [NSThread  currentThread]);
    }];
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download3----%@", [NSThread  currentThread]);
    }];
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"download4----%@", [NSThread  currentThread]);
        }
    }];
    NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download5----%@", [NSThread  currentThread]);
    }];
    //監(jiān)聽任務執(zhí)行完畢后 進行其他操作
    op5.completionBlock = ^{
        NSLog(@"op5執(zhí)行完畢---%@", [NSThread currentThread]);
    };
    
    // 設置依賴
    [op3 addDependency:op1];
    [op3 addDependency:op2];
    [op3 addDependency:op4];

    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:op3];
    [queue addOperation:op4];
    [queue addOperation:op5];
  • 線程之間的通信:

在子線程下載圖片后,回到主線程更新UI:

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    __block UIImage *image1 = nil;
    // 下載圖片1
    NSBlockOperation *download1 = [NSBlockOperation blockOperationWithBlock:^{
        // 圖片的網(wǎng)絡路徑
        NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
        // 加載圖片
        NSData *data = [NSData dataWithContentsOfURL:url];
        // 生成圖片
        image1 = [UIImage imageWithData:data];
    }];
    __block UIImage *image2 = nil;
    // 下載圖片2
    NSBlockOperation *download2 = [NSBlockOperation blockOperationWithBlock:^{
         // 圖片的網(wǎng)絡路徑
        NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"];
        // 加載圖片
        NSData *data = [NSData dataWithContentsOfURL:url];
        // 生成圖片
        image2 = [UIImage imageWithData:data];
    }];
    // 合成圖片
    NSBlockOperation *combine = [NSBlockOperation blockOperationWithBlock:^{
        // 開啟新的圖形上下文
        UIGraphicsBeginImageContext(CGSizeMake(100, 100));
        // 繪制圖片
        [image1 drawInRect:CGRectMake(0, 0, 50, 100)];
        image1 = nil;
        [image2 drawInRect:CGRectMake(50, 0, 50, 100)];
        image2 = nil;
        // 取得上下文中的圖片
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        // 結(jié)束上下文
        UIGraphicsEndImageContext();
        // 回到主線程顯示圖片
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.imageView.image = image;
        }];
    }];
    //設置依賴 保證下載完圖片 再去合成
    [combine addDependency:download1];
    [combine addDependency:download2];
    
    [queue addOperation:download1];
    [queue addOperation:download2];
    [queue addOperation:combine];

感謝閱讀
你的支持是我寫作的唯一動力

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末紫岩,一起剝皮案震驚了整個濱河市掌测,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌入宦,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宠哄,死亡現(xiàn)場離奇詭異蕴侧,居然都是意外死亡灰署,警方通過查閱死者的電腦和手機泉坐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門为鳄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人腕让,你說我怎么就攤上這事孤钦。” “怎么了纯丸?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵偏形,是天一觀的道長。 經(jīng)常有香客問我觉鼻,道長俊扭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任滑凉,我火速辦了婚禮统扳,結(jié)果婚禮上喘帚,老公的妹妹穿的比我還像新娘畅姊。我一直安慰自己咒钟,他們只是感情好,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布若未。 她就那樣靜靜地躺著朱嘴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪粗合。 梳的紋絲不亂的頭發(fā)上萍嬉,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機與錄音隙疚,去河邊找鬼壤追。 笑死,一個胖子當著我的面吹牛供屉,可吹牛的內(nèi)容都是我干的行冰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼伶丐,長吁一口氣:“原來是場噩夢啊……” “哼悼做!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起哗魂,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤肛走,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后录别,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體朽色,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年组题,在試婚紗的時候發(fā)現(xiàn)自己被綠了葫男。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡往踢,死狀恐怖腾誉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情峻呕,我是刑警寧澤利职,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站瘦癌,受9級特大地震影響猪贪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜讯私,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一热押、第九天 我趴在偏房一處隱蔽的房頂上張望西傀。 院中可真熱鬧,春花似錦桶癣、人聲如沸拥褂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饺鹃。三九已至,卻和暖如春间雀,著一層夾襖步出監(jiān)牢的瞬間悔详,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工惹挟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留茄螃,地道東北人。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓连锯,卻偏偏與公主長得像归苍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子萎庭,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容

  • NSThread 第一種:通過NSThread的對象方法 NSThread *thread = [[NSThrea...
    攻城獅GG閱讀 801評論 0 3
  • 在這篇文章中霜医,我將為你整理一下 iOS 開發(fā)中幾種多線程方案,以及其使用方法和注意事項驳规。當然也會給出幾種多線程的案...
    張戰(zhàn)威ican閱讀 603評論 0 0
  • 多線程基本概念 單核CPU肴敛,同一時間cpu只能處理1個線程,只有1個線程在執(zhí)行 。多線程同時執(zhí)行:是CPU快速的在...
    WeiHing閱讀 708評論 1 5
  • 作業(yè)1. 好好回想一下吗购,小時候呆呆看過什么医男。挑選一個印象或一幅畫面寫出來。 小時候呆呆看過什么已經(jīng)想不起了捻勉,不過最...
    狐皮克閱讀 176評論 2 0
  • 找一個懂你的人和找一個愛你的人不是一回事镀梭。 懂你什么呢,愛你可以是無條件的踱启,懂你不僅不可能报账,要“懂”也是有條件的。...
    子俠閱讀 603評論 1 2