iOS-多線程(GCD)

簡(jiǎn)介

什么是GCD
全稱是Grand Central Dispatch,可譯為“偉大的中樞調(diào)度器”
純C語(yǔ)言,提供了非常多強(qiáng)大的函數(shù)

  • GCD的優(yōu)勢(shì)
    GCD是蘋果公司為多核的并行運(yùn)算提出的解決方案
    GCD會(huì)自動(dòng)利用更多的CPU內(nèi)核(比如雙核、四核)
    GCD會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷毀線程)
    程序員只需要告訴GCD想要執(zhí)行什么任務(wù),不需要編寫任何線程管理代碼

任務(wù)和隊(duì)列

  • GCD中有2個(gè)核心概念
    任務(wù):執(zhí)行什么操作
    隊(duì)列:用來(lái)存放任務(wù)

  • GCD的使用就2個(gè)步驟
    定制任務(wù)
    確定想做的事情

  • 將任務(wù)添加到隊(duì)列中
    GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)取出,放到對(duì)應(yīng)的線程中執(zhí)行
    任務(wù)的取出遵循隊(duì)列的FIFO原則:先進(jìn)先出,后進(jìn)后出

執(zhí)行任務(wù)

  • GCD中有2個(gè)用來(lái)執(zhí)行任務(wù)的常用函數(shù)
    用同步的方式執(zhí)行任務(wù)
    dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
    queue:隊(duì)列
    block:任務(wù)

  • 用異步的方式執(zhí)行任務(wù)
    dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

  • 同步和異步的區(qū)別
    同步:只能在當(dāng)前線程中執(zhí)行任務(wù),不具備開啟新線程的能力
    異步:可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力

  • GCD中還有個(gè)用來(lái)執(zhí)行任務(wù)的函數(shù):
    dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
    在前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行,而且它后面的任務(wù)等它執(zhí)行完成之后才會(huì)執(zhí)行

隊(duì)列的類型

  • GCD的隊(duì)列可以分為2大類型
    并發(fā)隊(duì)列(Concurrent Dispatch Queue)
    可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動(dòng)開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))
    并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效

  • 串行隊(duì)列(Serial Dispatch Queue)
    讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù))

容易混淆的術(shù)語(yǔ)

  • 有4個(gè)術(shù)語(yǔ)比較容易混淆:同步、異步、并發(fā)、串行
    同步和異步主要影響:能不能開啟新的線程
    同步:只是在當(dāng)前線程中執(zhí)行任務(wù),不具備開啟新線程的能力
    異步:可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力

  • 并發(fā)和串行主要影響:任務(wù)的執(zhí)行方式
    并發(fā):多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行
    串行:一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù)

并發(fā)隊(duì)列

  • 使用dispatch_queue_create函數(shù)創(chuàng)建隊(duì)列
    dispatch_queue_t
    dispatch_queue_create(const char *label, // 隊(duì)列名稱
    dispatch_queue_attr_t attr); // 隊(duì)列的類型

  • 創(chuàng)建并發(fā)隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", DISPATCH_QUEUE_CONCURRENT);
    GCD默認(rèn)已經(jīng)提供了全局的并發(fā)隊(duì)列,供整個(gè)應(yīng)用使用,可以無(wú)需手動(dòng)創(chuàng)建
    使用dispatch_get_global_queue函數(shù)獲得全局的并發(fā)隊(duì)列
    dispatch_queue_t dispatch_get_global_queue(
    dispatch_queue_priority_t priority, // 隊(duì)列的優(yōu)先級(jí)
    unsigned long flags); // 此參數(shù)暫時(shí)無(wú)用,用0即可

  • 獲得全局并發(fā)隊(duì)列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

  • 全局并發(fā)隊(duì)列的優(yōu)先級(jí)
    ( #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
    ( #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(rèn)(中)
    ( #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
    ( #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后臺(tái)

串行隊(duì)列

  • GCD中獲得串行有2種途徑
    使用dispatch_queue_create函數(shù)創(chuàng)建串行隊(duì)列
    // 創(chuàng)建串行隊(duì)列(隊(duì)列類型傳遞NULL或者DISPATCH_QUEUE_SERIAL)
    dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", NULL);

  • 使用主隊(duì)列(跟主線程相關(guān)聯(lián)的隊(duì)列)
    主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列
    放在主隊(duì)列中的任務(wù),都會(huì)放到主線程中執(zhí)行
    使用dispatch_get_main_queue()獲得主隊(duì)列
    dispatch_queue_t queue = dispatch_get_main_queue();

線程間通信示例

  • 從子線程回到主線程

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
              ^{
                   // 執(zhí)行耗時(shí)的異步操作...
    dispatch_async(dispatch_get_main_queue(), ^{
                                 // 回到主線程,執(zhí)行UI刷新操作
                                                });
               });
    

延時(shí)執(zhí)行

  • iOS常見的延時(shí)執(zhí)行
    調(diào)用NSObject的方法
    [self performSelector:@selector(run)
    withObject:nil afterDelay:2.0];
    // 2秒后再調(diào)用self的run方法

  • 使用GCD函數(shù)
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
    (int64_t)(2.0 * NSEC_PER_SEC)),
    dispatch_get_main_queue(),
    ^{
    // 2秒后異步執(zhí)行這里的代碼...
    });

  • 使用NSTimer
    [NSTimer scheduledTimerWithTimeInterval:2.0
    target:self
    selector:@selector(test)
    userInfo:nil
    repeats:NO];

一次性代碼

  • 使用dispatch_once函數(shù)能保證某段代碼在程序運(yùn)行過(guò)程中只被執(zhí)行1次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    // 只執(zhí)行1次的代碼(這里面默認(rèn)是線程安全的)
    });

定時(shí)器

// 創(chuàng)建Timer

      self.timer=dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());

// 設(shè)置定時(shí)器的觸發(fā)時(shí)間(1秒后)和時(shí)間間隔(每隔2秒)

    dispatch_source_set_timer(self.timer,dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), 2 * NSEC_PER_SEC, 0);

// 設(shè)置回調(diào)

   dispatch_source_set_event_handler(self.timer, ^{
  NSLog(@"Timer %@", [NSThread currentThread]);
  });

// 開始定時(shí)器

  dispatch_resume(self.timer);

// 取消定時(shí)器

dispatch_cancel(self.timer);
self.timer = nil;

快速迭代

  • 使用dispatch_apply函數(shù)能進(jìn)行快速迭代遍歷
    dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index){
    // 執(zhí)行10次代碼,index順序不確定
    });

隊(duì)列組

  • 有這么1種需求
    首先:分別異步執(zhí)行2個(gè)耗時(shí)的操作
    其次:等2個(gè)異步操作都執(zhí)行完畢后,再回到主線程執(zhí)行操作

  • 如果想要快速高效地實(shí)現(xiàn)上述需求,可以考慮用隊(duì)列組

 dispatch_group_t group =  dispatch_group_create();
 dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
^{
// 執(zhí)行1個(gè)耗時(shí)的異步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
 ^{
// 執(zhí)行1個(gè)耗時(shí)的異步操作
});

//

  dispatch_group_notify(group, dispatch_get_main_queue(),
^{
        // 等前面的異步操作都執(zhí)行完畢后,回到主線程...
});

單例模式

  • 單例模式的作用
    可以保證在程序運(yùn)行過(guò)程,一個(gè)類只有一個(gè)實(shí)例,而且該實(shí)例易于供外界訪問(wèn)
    從而方便地控制了實(shí)例個(gè)數(shù),并節(jié)約系統(tǒng)資源

  • 單例模式的使用場(chǎng)合
    在整個(gè)應(yīng)用程序中,共享一份資源(這份資源只需要?jiǎng)?chuàng)建初始化1次)

  • ARC中,單例模式的實(shí)現(xiàn)
    在.m中保留一個(gè)全局的static的實(shí)例
    static id _instance;

  • 重寫allocWithZone:方法,在這里創(chuàng)建唯一的實(shí)例(注意線程安全)
    + (instancetype)allocWithZone:(struct _NSZone *)zone
    {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    _instance = [super allocWithZone:zone];
    });
    return _instance;
    }

  • 提供1個(gè)類方法讓外界訪問(wèn)唯一的實(shí)例
    + (instancetype)sharedInstance
    {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    _instance = [[self alloc] init];
    });
    return _instance;
    }

  • 實(shí)現(xiàn)copyWithZone:方法
    - (id)copyWithZone:(struct _NSZone *)zone
    {
    return _instance;
    }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評(píng)論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,634評(píng)論 3 419
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,653評(píng)論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,835評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,235評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,459評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,000評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,819評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,004評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,257評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評(píng)論 1 288
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,717評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,003評(píng)論 2 374

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

  • 多線程學(xué)習(xí)筆記-GCD 我把這篇文章所用到的代碼總結(jié)到這里->GCD項(xiàng)目總結(jié)下載地址-GCD-wxk可以下載參考 ...
    wxkkkkk閱讀 541評(píng)論 0 2
  • 一、簡(jiǎn)介在iOS所有實(shí)現(xiàn)多線程的方案中,GCD應(yīng)該是最有魅力的,因?yàn)镚CD本身是蘋果公司為多核的并行運(yùn)算提出的解決...
    MYS_iOS_8801閱讀 576評(píng)論 0 0
  • 目錄:iOS多線程(一)--pthread、NSThreadiOS多線程(二)--GCD詳解iOS多線程(三)--...
    Claire_wu閱讀 1,087評(píng)論 0 6
  • 一、基本概念 線程是用來(lái)執(zhí)行任務(wù)的,線程徹底執(zhí)行完任務(wù)A才能執(zhí)行任務(wù)B,為了同時(shí)執(zhí)行兩個(gè)任務(wù),產(chǎn)生了多線程 1、進(jìn)...
    空白Null閱讀 707評(píng)論 0 3
  • 今年的生日,果然也還是一個(gè)人過(guò)。
    從良人閱讀 161評(píng)論 0 0