NSOperation宦棺、Queue使用注意點總結(jié)

NSOperation施流、NSOperationQueue 是蘋果提供給我們的一套多線程解決方案。實際上 NSOperation确憨、NSOperationQueue 是基于 GCD 更高一層的封裝译荞,完全面向?qū)ο蟆5潜?GCD 更簡單易用休弃、代碼可讀性也更高吞歼。

1.NSOperation基本使用

NSOperation可以調(diào)用start方法來執(zhí)行任務(wù),但默認是同步執(zhí)行的
NSOperation是個抽象類塔猾,并不具備封裝操作的能力篙骡,必須使用它的子類(在第三條介紹子類)

  • 先將需要執(zhí)行的操作封裝到一個NSOperation對象中
  • 然后將NSOperation對象添加到NSOperationQueue中
  • 系統(tǒng)會自動將NSOperationQueue中的NSOperation取出來
  • 將取出的NSOperation封裝的操作放到一條新線程中執(zhí)行

2.NSOperationQueue 隊列

    //創(chuàng)建操作(任務(wù))
    NSOperationQueue  *queue = [[NSOperationQueue alloc]init];
    
    NSInvocationOperation  *operationInvocation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoad1) object:nil];
    NSBlockOperation  *operationblock = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"downLoad3-----%@",[NSThread currentThread]);
        
    }];
    //添加任務(wù)
    [queue addOperation:operationInvocation];//自動調(diào)用 [op start]
    [queue addOperation:operationblock];//自動調(diào)用 [op start]
  • 通過 [[NSOperationQueue alloc]init]創(chuàng)建的操作隊列,其內(nèi)添加的任務(wù)在子線程執(zhí)行。
  • 通過[NSOperationQueue mainQueue] 獲取的是主操作隊列糯俗,其內(nèi)添加的任務(wù)(NSOperation)在主線程執(zhí)行尿褪。
  • 如果將NSOpeeration添加到NSOperationQueue(操作隊列)中,系統(tǒng)自動異步執(zhí)行NSOperation中的操作得湘。

添加操作到NSOperationQueue中
//add后的任務(wù)不需要調(diào)用-start就會自動執(zhí)行

  • (void)addOperation:(NSOperation *)op;
  • (void)addOperationWithBlock

3.NSOperation的子類

3.1 NSInvocationOperation

//如果是在主線程創(chuàng)建杖玲,就在主線程執(zhí)行任務(wù)。如果是子線程忽刽,那就在子線程
  NSInvocationOperation  *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];
  [operation start];
  • 默認情況下天揖,調(diào)用了start方法后并不會開一條新線程去執(zhí)行操作,而是在當(dāng)前線程同步執(zhí)行操作
  • 只有將NSOperation放到一個NSOperationQueue中跪帝,才會異步執(zhí)行操作

3.2NSBlockOperation

    //包裝的任務(wù)在主線程
    NSBlockOperation  *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1  --- %@",[NSThread currentThread]);
    }];
    //再添加的任務(wù) 會在新子線程執(zhí)行
    [operation addExecutionBlock:^{
        NSLog(@"2 --- %@",[NSThread currentThread]);  
    }];
    [operation start];
  • 只要NSBlockOperation封裝的操作數(shù) > 1今膊,就會異步執(zhí)行操作

3.3自定義NSOperation

  • 自定義NSOperation的步驟很簡單,只要重寫- (void)main方法伞剑,在里面實現(xiàn)想執(zhí)行的任務(wù)斑唬。當(dāng)然如果結(jié)構(gòu)很復(fù)雜的自定義NSOperation還需要實現(xiàn)- (BOOL)isConcurrent是否并發(fā)等方法。
  • 經(jīng)常通過- (BOOL)isCancelled方法檢測操作是否被取消黎泣,對取消做出響應(yīng)
//需要執(zhí)行的任務(wù)
- (void)main{
    
    for (int i =0; i<10088; i++) {
        NSLog(@"XBSOpertion----下載任務(wù)%@",[NSThread currentThread]);
    }
    //這句寫與否直接就看出你的水平
    if (self.isCancelled) return;
    
    for (int i =0; i<10088; i++) {
        NSLog(@"XBSOpertion----下載任務(wù)%@",[NSThread currentThread]);
    }
}

4.最大并發(fā)數(shù)maxConcurrentOperationCount

系統(tǒng)默認最大并發(fā)數(shù)是NSOperationQueueDefaultMaxConcurrentOperationCount = -1.

  • maxConcurrentOperationCount = 0 不執(zhí)行隊列
  • maxConcurrentOperationCount = 1 串行隊列
  • maxConcurrentOperationCount > 1 并發(fā)隊列

5.NSOperation掛起和取消

注意:
1.這里的暫停和取消(包括操作的取消和隊列的取消)并不代表可以將當(dāng)前的操作立即取消恕刘,而是當(dāng)當(dāng)前的操作執(zhí)行完畢之后不再執(zhí)行新的操作。
2.暫停和取消的區(qū)別就在于:暫停操作之后還可以恢復(fù)操作抒倚,繼續(xù)向下執(zhí)行褐着;而取消操作之后,所有的操作就清空了托呕,無法再接著執(zhí)行剩下的操作

5.1掛起suspended.

  • suspended YES:暫停(掛起)隊列 NO:恢復(fù)隊列

5.2 取消

  • 單個任務(wù)取消 [operation cancel];
  • 整個操作隊列所有未開始任務(wù)的取消 [self.queue cancelAllOperations]

6.依賴和監(jiān)聽

6.1依賴[queue addExecution]

6.1.1 同隊列內(nèi)依賴

NSOperation之間可以設(shè)置依賴來保證執(zhí)行順序
比如一定要讓操作A執(zhí)行完后含蓉,才能執(zhí)行操作B,可以這么寫
[operationB addDependency:operationA]; // 操作B依賴于操作A

6.1.2 跨隊列依賴

可以在不同queue的NSOperation之間創(chuàng)建依賴關(guān)系


跨隊列依賴.jpeg

圖解:NSOperation3依賴于NSOperation2项郊,NSOperation2又依賴于其他隊列的NSOperation6馅扣,NSOperation6又依賴于NSOperation1。

只要是個NSOperation對象就可以建立依賴着降,非常強大差油。

注意:不能相互依賴。比如A依賴B任洞,B依賴A

6.2 監(jiān)聽

可以監(jiān)聽一個操作的執(zhí)行完畢

  • (void (^)(void))completionBlock;
  • (void)setCompletionBlock:(void (^)(void))block;

注意點:蘋果官方描述:
A finished (or canceled) operation is still given a chance to execute its completion block before it is removed from the queue

一個已經(jīng)完成(或者已經(jīng)被取消)的操作在被移除操作隊列之前仍然有機會去執(zhí)行completion block蓄喇。

7.知識實踐

下載兩張圖片,然后合成一張顯示處出啦

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    NSOperationQueue  *queueOp = [[NSOperationQueue alloc]init];
    __block UIImage  *image1 = nil;
    
    //下載圖片1
    NSBlockOperation  *downLoad1 = [NSBlockOperation blockOperationWithBlock:^{
        NSURL  *url = [NSURL URLWithString:@"https://upload-images.jianshu.io/upload_images/6687791-5ad29d1a5c1c84db.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"];

        image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
        
    }];

    __block  UIImage  *image2 = nil;
    NSBlockOperation  *downLoad2 = [NSBlockOperation blockOperationWithBlock:^{
       
        NSURL  *url = [NSURL URLWithString:@"https://upload-images.jianshu.io/upload_images/6687791-2a51b4b27040ed41.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"];
        
        image2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
    }];
 
    
    
    //4.等待兩張圖片下載完成交掏,將兩張圖片合成一張
    
    NSBlockOperation  *combine = [NSBlockOperation blockOperationWithBlock:^{
        //開啟新的圖形上下文
        UIGraphicsBeginImageContext(CGSizeMake(300, 300));
        //繪制圖片
        [image1 drawInRect:CGRectMake(0, 0, 300, 150)];
        image1 = nil;
        [image2 drawInRect:CGRectMake(0, 150, 300, 150)];
        image2 = nil;
        //取得圖形上下文中的圖片
        UIImage  *newImage = UIGraphicsGetImageFromCurrentImageContext();
        //結(jié)束上下文
        UIGraphicsEndImageContext();
        //回到主線程顯示圖片
       
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.imageView.image = newImage;
        }];
        
        
    }];
    //combine合成任務(wù)的執(zhí)行依賴 downLoad1  和 downLoad2的執(zhí)行完成
    [combine addDependency:downLoad1];
    [combine addDependency:downLoad2];
    
    //三個任務(wù)添加到操作隊列中
    [queueOp addOperation:downLoad1];
    [queueOp addOperation:downLoad2];
    [queueOp addOperation:combine];
    
}

如果您有什么疑問或者發(fā)現(xiàn)書寫歧義妆偏,非常感激您能留言~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市耀销,隨后出現(xiàn)的幾起案子楼眷,更是在濱河造成了極大的恐慌,老刑警劉巖熊尉,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件罐柳,死亡現(xiàn)場離奇詭異,居然都是意外死亡狰住,警方通過查閱死者的電腦和手機张吉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來催植,“玉大人肮蛹,你說我怎么就攤上這事〈茨希” “怎么了伦忠?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長稿辙。 經(jīng)常有香客問我昆码,道長,這世上最難降的妖魔是什么邻储? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任赋咽,我火速辦了婚禮,結(jié)果婚禮上吨娜,老公的妹妹穿的比我還像新娘脓匿。我一直安慰自己,他們只是感情好宦赠,可當(dāng)我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布陪毡。 她就那樣靜靜地躺著,像睡著了一般袱瓮。 火紅的嫁衣襯著肌膚如雪缤骨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天尺借,我揣著相機與錄音绊起,去河邊找鬼。 笑死燎斩,一個胖子當(dāng)著我的面吹牛虱歪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播栅表,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼笋鄙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了怪瓶?” 一聲冷哼從身側(cè)響起萧落,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后找岖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體陨倡,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年许布,在試婚紗的時候發(fā)現(xiàn)自己被綠了兴革。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜜唾,死狀恐怖杂曲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情袁余,我是刑警寧澤擎勘,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站颖榜,受9級特大地震影響货抄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜朱转,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一蟹地、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧藤为,春花似錦怪与、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至存淫,卻和暖如春耘斩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背桅咆。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工括授, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人岩饼。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓荚虚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親籍茧。 傳聞我的和親對象是個殘疾皇子版述,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,455評論 2 359

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