iOS GCD常規(guī)使用

前言:本文的主要內(nèi)容是:

  1. iOS中常用的幾種多線程技術(shù)比較
  2. GCD知識鋪墊
  3. GCD的使用
  4. GCD中一些系統(tǒng)提供的其他常用的dispatch方法

1. iOS中常用的幾種多線程技術(shù)比較

pthread:通用于Unix/Linux/Windows的C語言線程管理API掘剪,可移植性強(qiáng)寡痰, 但是使用繁瑣颗圣,需要使用者管理線程生命周期。
NSThread:使用Objective-C實現(xiàn)蹂楣,輕量級的線程管理,但也需要手動管理線程的生命周期
NSOperation:基于GCD蟀苛,使用Objective-C實現(xiàn)的面向?qū)ο蟮木€程管理撤蚊,比GCD更高級,但是處理簡單任務(wù)會比GCD代碼更多辽俗。
GCD : 旨在優(yōu)化多核環(huán)境中的并發(fā)操作,簡單易用疾渣,效率高,速度快崖飘,能自動管理線程生命周期(創(chuàng)建線程、調(diào)度任務(wù)杈女、銷毀線程)朱浴。
線程的生命周期圖:

線程的生命周期.png

2. GCD知識鋪墊

** 競爭&同步:兩個線程搶奪同一個資源吊圾,就會競爭,為了防止競爭翰蠢,一個線程擁有資源的時候项乒,會對資源加鎖,另一個線程就要等待解鎖以后再擁有這個資源梁沧,這叫同步檀何。
** 死鎖:
兩個線程互相等待對方釋放資源
主線程&后臺線程:主線程也叫前臺線程,程序啟動的默認(rèn)線程廷支,操作UI的線程频鉴。后臺線程,即非主線程恋拍,用于不影響主線程的完成一些任務(wù)
并行隊列&串行隊列:并行垛孔,就是隊列中幾個任務(wù)一起完成。串行施敢,就是隊列幾個任務(wù)一個接著一個完成周荐。
同步線程&異步線程:同步執(zhí)行線程,等待新線程執(zhí)行完以后僵娃,再繼續(xù)執(zhí)行當(dāng)前線程概作,很少用到。異步執(zhí)行線程默怨,在執(zhí)行新線程的同時讯榕,繼續(xù)執(zhí)行當(dāng)前線程,常用先壕。
并發(fā)VS并行:并行是指兩個或者多個事件在同一時刻發(fā)生瘩扼;而并發(fā)是指兩個或多個事件在同一時間間隔內(nèi)發(fā)生。并行是基于多核設(shè)備的垃僚,并發(fā)一般基于CPU的分時操作集绰。

3. GCD的使用

GCD的使用步驟

  • 創(chuàng)建線程隊列:主隊列,全局并行隊列谆棺,手動創(chuàng)建串行隊列
  • 選擇執(zhí)行方式:同步(較少使用)栽燕,異步,延時
  • 添加需要執(zhí)行的任務(wù):也就是想要創(chuàng)建隊列做什么改淑,以Block塊語句形式創(chuàng)建
  • 任務(wù)被執(zhí)行:Block按照設(shè)計被執(zhí)行

創(chuàng)建線程隊列

主隊列:
dispatch_queue_t queue = dispatch_get_main_queue();
全局并行隊列:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
手動創(chuàng)建串行隊列:
dispatch_queue_t queue = dispatch_queue_create("com.realank.GCDDemo.myQueue", NULL);

選擇線程執(zhí)行方式

異步:
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
同步
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
延時:
void dispatch_after(dispatch_time_t when,dispatch_queue_t queue, dispatch_block_t block);

GCD術(shù)語解析

術(shù)語解析.png

同步異步在不同線程隊列的執(zhí)行情況.png

異步(async)執(zhí)行線程
1碍岔、 異步后臺線程主要用途:執(zhí)行較慢的任務(wù),例如大量計算朵夏,網(wǎng)絡(luò)請求等

//異步后臺并發(fā)線程
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"在異步并行隊列中執(zhí)行");
    });

//自創(chuàng)建的異步后臺串行線程蔼啦。
dispatch_queue_t queue dispatch_queue_create("com.realank.GCDDemo.myQueue", NULL);
dispatch_async(queue, ^{
        NSLog(@"在異步串行隊列中執(zhí)行");
    });

2、異步主線程

//  主要用途:用于在后臺線程的任務(wù)將要完成時仰猖,切換到主線程更新UI
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"在異步主線程中執(zhí)行");
    });

同步(sync)執(zhí)行線程
1捏肢、同步后臺線程
主要用途:在新線程中執(zhí)行任務(wù)奈籽,并且等待線程執(zhí)行完畢再向后執(zhí)行,幾乎不用

//同步后臺并行線程
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     NSLog(@"在同步并行隊列中執(zhí)行");
 });
// 同步后臺串行線
 dispatch_queue_t queue = dispatch_queue_create("com.realank.GCDDemo.myQueue", NULL);
 dispatch_sync(queue, ^{
     NSLog(@"在同步串行隊列中執(zhí)行");
 });

2鸵赫、同步主線程(慎用)
主要用途:只有在其它線程中才可能執(zhí)行此方法衣屏,否則會死鎖

dispatch_sync(dispatch_get_main_queue(), ^{
    NSLog(@“在同步主線程中執(zhí)行,慎用辩棒,否則會死鎖”);
});

注意 不要嵌套使用同步執(zhí)行的串行隊列任務(wù)(會產(chǎn)生死鎖,打破嵌套狼忱、同步、串行其中一個條件就可以)一睁,如嵌套使用同步執(zhí)行的并發(fā)隊列任務(wù)(不會產(chǎn)生死鎖钻弄,程序正常運(yùn)行)。

注意循環(huán)強(qiáng)引用

不要在Block中使用self.png
__weak __typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        weakSelf.string = @“hello";
    });

GCD中一些系統(tǒng)提供的常用dispatch方法

  • dispatch_after延時添加到隊列
    主要用途:dispatch_after只是延時提交block卖局,并不是延時后立即執(zhí)行斧蜕,并不能做到精確控制。
dispatch_time_t delayTime3 = dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC);
dispatch_time_t delayTime2 = dispatch_time(DISPATCH_TIME_NOW, 2*NSEC_PER_SEC);
dispatch_queue_t mainQueue = dispatch_get_main_queue();
NSLog(@"current task");
dispatch_after(delayTime3, mainQueue, ^{
  NSLog(@"3秒之后添加到隊列");
});
dispatch_after(delayTime2, mainQueue, ^{
   NSLog(@"2秒之后添加到隊列");
});
NSLog(@"next task");

控制臺輸出如下:

2015-11-19 15:50:19.369 Whisper[2725:172593] current task
2015-11-19 15:50:19.370 Whisper[2725:172593] next task
2015-11-19 15:50:21.369 Whisper[2725:172593] 2秒之后添加到隊列
2015-11-19 15:50:22.654 Whisper[2725:172593] 3秒之后添加到隊列
  • Group queue (隊列組)

使用場景: 同時下載多個圖片砚偶,所有圖片下載完成之后去更新UI(需要回到主線程)批销。
原理:使用函數(shù)dispatch_group_create創(chuàng)建dispatch group,然后使用函數(shù)dispatch_group_async來將要執(zhí)行的block任務(wù)提交到一個dispatch queue。同時將他們添加到一個組染坯,等要執(zhí)行的block任務(wù)全部執(zhí)行完成之后均芽,通過dispatch_group_notify,可以直接監(jiān)聽組里所有線程完成情況。

    1   dispatch_queue_t conCurrentGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    2   dispatch_queue_t mainQueue = dispatch_get_main_queue();
    3   dispatch_group_t groupQueue = dispatch_group_create();
    4   NSLog(@"current task");
    5   dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{
    6      NSLog(@"并行任務(wù)1");
    7   });
    8   dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{
    9      NSLog(@"并行任務(wù)2");
    10  });
    11  dispatch_group_notify(groupQueue, mainQueue, ^{
    12     NSLog(@"groupQueue中的任務(wù) 都執(zhí)行完成,回到主線程更新UI");
    13  });
    14  NSLog(@"next task");

控制臺輸出:

2015-11-19 13:47:55.117 Whisper[1645:97116] current task
2015-11-19 13:47:55.117 Whisper[1645:97116] next task
2015-11-19 13:47:55.119 Whisper[1645:97178] 并行任務(wù)1
2015-11-19 13:47:55.119 Whisper[1645:97227] 并行任務(wù)2
2015-11-19 13:47:55.171 Whisper[1645:97116] groupQueue中的任務(wù) 都執(zhí)行完成,回到主線程更新UI
  • 阻塞當(dāng)前線程dispatch_group_wait
    dispatch_group_wait 单鹿,它會阻塞當(dāng)前線程掀宋,直到組里面所有的任務(wù)都完成或者等到某個超時發(fā)生。
    1   dispatch_group_t groupQueue = dispatch_group_create();
    2   dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC);
    3   dispatch_queue_t conCurrentGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    4   NSLog(@"current task");
    5   dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{
    6   
    7      long isExecuteOver = dispatch_group_wait(groupQueue, delayTime);
    8      if (isExecuteOver) {
    9          NSLog(@"wait over");
    10     } else {
    11         NSLog(@"not over");
    12     }
    13     NSLog(@"并行任務(wù)1");
    14  });
    15  dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{
    16     NSLog(@"并行任務(wù)2");
    17  });

控制臺輸出如下:

2015-11-19 14:37:29.514 Whisper[2426:126683] current task
2015-11-19 14:37:29.518 Whisper[2426:126791] 并行任務(wù)2
2015-11-19 14:37:39.515 Whisper[2426:126733] wait over
2015-11-19 14:37:39.516 Whisper[2426:126733] 并行任務(wù)1
  • dispatch_apply多次執(zhí)行
    dispatch_apply函數(shù):dispatch_apply是同步執(zhí)行的函數(shù),不會立刻返回仲锄,在執(zhí)行完block中的任務(wù)后才會返回劲妙。功能是把一項任務(wù)提交到隊列中多次執(zhí)行,隊列可以是串行也可以是并行儒喊。
    為了不阻塞主線程镣奋,dispatch_apply正確使用方法是把dispatch_apply放在異步隊列中調(diào)用,然后執(zhí)行完成后通知主線程
使用示例:
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
NSLog(@"current task");
dispatch_async(globalQueue, ^{
dispatch_queue_t applyQueue = dispatch_get_global_queue(0, 0);
//第一個參數(shù)怀愧,3--block執(zhí)行的次數(shù)
//第二個參數(shù)侨颈,applyQueue--block任務(wù)提交到的隊列
//第三個參數(shù),block--需要重復(fù)執(zhí)行的任務(wù)
dispatch_apply(3, applyQueue, ^(size_t index) {
      NSLog(@"current index %@",@(index));
      sleep(1);
});
NSLog(@"dispatch_apply 執(zhí)行完成");
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{
      NSLog(@"回到主線程更新UI");
});
});
NSLog(@"next task");
```
控制臺輸出如下:
```
2015-11-19 16:24:45.015 Whisper[4034:202269] current task
2015-11-19 16:24:45.016 Whisper[4034:202269] next task
2015-11-19 16:24:45.016 Whisper[4034:202347] current index 0
2015-11-19 16:24:45.016 Whisper[4034:202344] current index 1
2015-11-19 16:24:45.016 Whisper[4034:202345] current index 2
2015-11-19 16:24:46.021 Whisper[4034:202347] dispatch_apply 執(zhí)行完成
2015-11-19 16:24:46.021 Whisper[4034:202269] 回到主線程更新UI
嵌套使用dispatch_apply會導(dǎo)致死鎖芯义。
```
* dispatch_once 執(zhí)行一次
 dispatch_once保證在app運(yùn)行期間哈垢,block中的代碼只執(zhí)行一次
    ?   經(jīng)典使用場景---單例
    ?   單例對象ShareManager的定義:

```
    2    ShareManager的.h文件
    3   #import <Foundation/Foundation.h>
    4   @interface ShareManager : NSObject
    5   @property (nonatomic, copy) NSString *someProperty;
    6   + (ShareManager *)shareManager;
    7   + (ShareManager *)sharedManager;
    8   @end
    9   
    10  ShareManager的.m文件
    11  #import "ShareManager.h"
    12  @implementation ShareManager
    13  static ShareManager *sharedManager = nil;
    14  //GCD實現(xiàn)單例功能
    15  + (ShareManager *)shareManager
    16  {
    17   static dispatch_once_t onceToken;
    18   dispatch_once(&onceToken, ^{
    19       sharedManager = [[self alloc] init];
    20   });
    21   return sharedManager;
    22  }
    23  //在ARC下,非GCD扛拨,實現(xiàn)單例功能
    24  + (ShareManager *)sharedManager
    25  {
    26   @synchronized(self) {
    27       if (!sharedManager) {
    28           sharedManager = [[self alloc] init];
    29       }
    30   }
    31   return sharedManager;
    32  }
    33  - (instancetype)init{
    34   self = [super init];
    35   if (self) {
    36        _someProperty =@"Default Property Value";
    37   }
    38   return self;
    39  }
    40  @end
    41  
    42  ShareManager的使用
    43  #import "ShareManager.h"
    44  在需要使用的函數(shù)中耘分,直接調(diào)用下面的方法
    45  ShareManager *share = [ShareManager sharedManager];
    46  NSLog(@"share is %@",share.someProperty);

```
* dispatch_barrier_async柵欄的作用
功能:是在并行隊列中,等待在dispatch_barrier_async之前加入的隊列全部執(zhí)行完成之后(這些任務(wù)是并發(fā)執(zhí)行的)再執(zhí)行dispatch_barrier_async中的任務(wù),dispatch_barrier_async中的任務(wù)執(zhí)行完成之后陶贼,再去執(zhí)行在dispatch_barrier_async之后加入到隊列中的任務(wù)(這些任務(wù)是并發(fā)執(zhí)行的)啤贩。
圖解:
![dispatch_barrier_async柵欄的作用.jpg](http://upload-images.jianshu.io/upload_images/2050812-d0782d71b810774b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
使用示例:
```
dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(conCurrentQueue, ^{
  NSLog(@"dispatch 1");
});
dispatch_async(conCurrentQueue, ^{
   NSLog(@"dispatch 2");
});
dispatch_barrier_async(conCurrentQueue, ^{
   NSLog(@"dispatch barrier");
});
dispatch_async(conCurrentQueue, ^{
   NSLog(@"dispatch 3");
});
dispatch_async(conCurrentQueue, ^{
   NSLog(@"dispatch 4");
});
```
控制臺輸出:
```
2015-11-19 18:12:34.125 Whisper[22633:297257] dispatch 1
2015-11-19 18:12:34.125 Whisper[22633:297258] dispatch 2
2015-11-19 18:12:34.126 Whisper[22633:297258] dispatch barrier
2015-11-19 18:12:34.127 Whisper[22633:297258] dispatch 3
2015-11-19 18:12:34.127 Whisper[22633:297257] dispatch 4

```
參考文章
[iOS中GCD的使用小結(jié)](http://www.reibang.com/p/ae786a4cf3b1)
[GCD 深入理解](http://www.cocoachina.com/industry/20140428/8248.html)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末待秃,一起剝皮案震驚了整個濱河市拜秧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌章郁,老刑警劉巖枉氮,帶你破解...
    沈念sama閱讀 223,207評論 6 521
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異暖庄,居然都是意外死亡聊替,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,455評論 3 400
  • 文/潘曉璐 我一進(jìn)店門培廓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惹悄,“玉大人,你說我怎么就攤上這事肩钠∑郏” “怎么了?”我有些...
    開封第一講書人閱讀 170,031評論 0 366
  • 文/不壞的土叔 我叫張陵价匠,是天一觀的道長当纱。 經(jīng)常有香客問我,道長踩窖,這世上最難降的妖魔是什么坡氯? 我笑而不...
    開封第一講書人閱讀 60,334評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮洋腮,結(jié)果婚禮上箫柳,老公的妹妹穿的比我還像新娘。我一直安慰自己啥供,他們只是感情好悯恍,可當(dāng)我...
    茶點故事閱讀 69,322評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著滤灯,像睡著了一般坪稽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鳞骤,一...
    開封第一講書人閱讀 52,895評論 1 314
  • 那天窒百,我揣著相機(jī)與錄音,去河邊找鬼豫尽。 笑死篙梢,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的美旧。 我是一名探鬼主播渤滞,決...
    沈念sama閱讀 41,300評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼贬墩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了妄呕?” 一聲冷哼從身側(cè)響起陶舞,我...
    開封第一講書人閱讀 40,264評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绪励,沒想到半個月后肿孵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,784評論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疏魏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,870評論 3 343
  • 正文 我和宋清朗相戀三年停做,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片大莫。...
    茶點故事閱讀 40,989評論 1 354
  • 序言:一個原本活蹦亂跳的男人離奇死亡蛉腌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出只厘,到底是詐尸還是另有隱情烙丛,我是刑警寧澤,帶...
    沈念sama閱讀 36,649評論 5 351
  • 正文 年R本政府宣布懈凹,位于F島的核電站蜀变,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏介评。R本人自食惡果不足惜库北,卻給世界環(huán)境...
    茶點故事閱讀 42,331評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望们陆。 院中可真熱鬧寒瓦,春花似錦、人聲如沸坪仇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,814評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽椅文。三九已至喂很,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間皆刺,已是汗流浹背少辣。 一陣腳步聲響...
    開封第一講書人閱讀 33,940評論 1 275
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留羡蛾,地道東北人漓帅。 一個月前我還...
    沈念sama閱讀 49,452評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親忙干。 傳聞我的和親對象是個殘疾皇子器予,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,995評論 2 361

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