GCD的一般用法

簡(jiǎn)介

GCD(Grand Central Dispatch)是由蘋果開發(fā)的一個(gè)多核編程的解決方案。iOS4.0+才能使用,GCD是基于C語(yǔ)言的,所以在多線程方面比NSThread, NSOperation高效很多。

用途

1,CGD多線程
2,GCD定時(shí)器
3,CGD連續(xù)調(diào)用n次
4,CGD單例的實(shí)現(xiàn)
5,CGD延遲調(diào)用
6,CGD任務(wù)組
7,CGD任務(wù)柵欄

詳細(xì)講解

1,CGD多線程

dispatch_async:異步調(diào)度:不會(huì)等待任務(wù)執(zhí)行完成。
dispatch_sync:同步調(diào)度:等待任務(wù)執(zhí)行完成才能繼續(xù)。
dispatch_get_main_queue( ) 獲得主線程隊(duì)列
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)獲得分線程隊(duì)列,DISPATCH_QUEUE_PRIORITY_DEFAULT為執(zhí)行優(yōu)先級(jí),這里為默認(rèn)優(yōu)先級(jí)

我們要在什么時(shí)候使用多線程呢?
首先我們要知道app默認(rèn)是在主線程中運(yùn)行,如果我們要執(zhí)行一些比較耗時(shí)的工作,比如請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù),在網(wǎng)絡(luò)不是很好,或者數(shù)據(jù)比較大的時(shí)候,沒(méi)有辦法立即完成動(dòng)作,在完成數(shù)據(jù)請(qǐng)求任務(wù)之前,主線程一直被占用,app則會(huì)無(wú)法響應(yīng)任何操作,嚴(yán)重影響用戶體驗(yàn),這時(shí)候我們就用到多線程,把耗時(shí)的操作全部扔到分線程里面去,防止阻塞主線程。

下面為一個(gè)網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求,首先進(jìn)入分線程,然后請(qǐng)求數(shù)據(jù)(耗時(shí)操作),當(dāng)數(shù)據(jù)請(qǐng)求成功時(shí),一定要回到主線程賦值刷新界面。

       //進(jìn)入分線程
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
           //耗時(shí)操作
            NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://img3.douban.com/view/movie_poster_cover/lpst/public/p480747492.jpg"]];
            //回到主線程刷新界面
            dispatch_async(dispatch_get_main_queue( ), ^{
                imageView.image = [UIImage imageWithData:data];
            });
        });

注意?。?!
大家在使用多線程的時(shí)候盡量使用異步調(diào)度dispatch_async,因?yàn)橥秸{(diào)度dispatch_sync如果注意不到有可能造成線程阻塞,也就是死鎖。
舉個(gè)栗子,下面為典型的死鎖,死鎖產(chǎn)生的原因是使用同步調(diào)度調(diào)用當(dāng)前線程(一般都是主線程)造成的。

NSLog(@"我肯定是可以執(zhí)行的");
    //我要等NSLog(@"我要等dispatch_sync執(zhí)行完我在執(zhí)行");執(zhí)行完我在執(zhí)行
    dispatch_sync(mainQueue, ^{
        NSLog(@"我要等dispatch_sync執(zhí)行完我在執(zhí)行");
    });
    
    NSLog(@"前面線程堵住啦,我執(zhí)行不了");

大家思考下為什么異步調(diào)度不會(huì)造成死鎖?

2,GCD定時(shí)器

如果大家在使用定時(shí)器的時(shí)候,在滑動(dòng)屏幕的時(shí)候定時(shí)器會(huì)停止的話,是因?yàn)槎〞r(shí)器創(chuàng)建在了主線程,在創(chuàng)建timer的時(shí)候把最后一個(gè)參數(shù)改成dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),創(chuàng)建在分線程即可

    //創(chuàng)建時(shí)間源
    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    //設(shè)置時(shí)間源
    /*
     參數(shù)1:timer
     參數(shù)2:時(shí)間間隔
     參數(shù)3:時(shí)間誤差
     */
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0);
    //執(zhí)行的任務(wù)
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"把要使用定時(shí)器執(zhí)行的代碼寫在這個(gè)block里");
    });
    //開啟定時(shí)器
    dispatch_resume(timer);
    //定時(shí)器銷毀
    dispatch_cancel(timer);

注意?。?/strong>
定時(shí)器一定要記得手動(dòng)銷毀,不然會(huì)發(fā)生內(nèi)存泄漏。

3,CGD連續(xù)調(diào)用n次
dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t t) {
        NSLog(@"xxxxx");
    });
4,CGD單例的實(shí)現(xiàn)
//線程安全
    static UIView *view = nil;

//該代碼只會(huì)執(zhí)行一次,一般用作單例
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
            view = [[UIView alloc] initWithFrame:self.view.bounds];
    });
5,CGD延遲調(diào)用

 /*
     參數(shù)1:開始計(jì)時(shí)時(shí)間,DISPATCH_TIME_NOW為現(xiàn)在開始計(jì)時(shí)
     參數(shù)2:延遲時(shí)間,這里為三秒,可根據(jù)自己需求自行修改
     參數(shù)3:執(zhí)行隊(duì)列,這里為主隊(duì)列
     */
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"代碼寫這里");
    });
6,CGD任務(wù)組

在多線程中異步調(diào)度執(zhí)行任務(wù)時(shí),是沒(méi)有固定順序的,所有在異步調(diào)度下有一個(gè)任務(wù)需要最后執(zhí)行,則可以使用任務(wù)組。

    //比如有3個(gè)任務(wù):A,B,C.  A,B先異步執(zhí)行,最后執(zhí)行C
    //創(chuàng)建隊(duì)列
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"A");
        sleep(1);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"B");
        sleep(1);
    });
    
    //最后通知要執(zhí)行的任務(wù)
    dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"C");
        sleep(1);
    });

7,CGD任務(wù)柵欄

如上所述,異步調(diào)度執(zhí)行任務(wù)沒(méi)有固定順序,而柵欄把任務(wù)分開,先執(zhí)行柵欄之前的,再執(zhí)行柵欄之后的,下面例子AB任務(wù)順序不固定,DE任務(wù)順序不固定,但是AB一定在C之前執(zhí)行,DE在C之后執(zhí)行

//自定義隊(duì)列
    /*
     參數(shù)1:隊(duì)列名字
     參數(shù)2:串行/并行 
           DISPATCH_QUEUE_SERIAL(串行隊(duì)列)/DISPATCH_QUEUE_CONCURRENT(并行隊(duì)列)
     */
    dispatch_queue_t customQueue = dispatch_queue_create("customQueue", DISPATCH_QUEUE_CONCURRENT);
    //先執(zhí)行AB
    dispatch_async(customQueue, ^{
        NSLog(@"任務(wù)A");
        sleep(1);
    });
    
    dispatch_async(customQueue, ^{
        NSLog(@"任務(wù)B");
        sleep(1);
    });
    
    //障礙物,線程?hào)艡?執(zhí)行C
    dispatch_barrier_async(customQueue, ^{
        NSLog(@"任務(wù)C");
        sleep(1);
    });
    //再執(zhí)行DE
    dispatch_async(customQueue, ^{
        NSLog(@"任務(wù)D");
        sleep(1);
    });
    
    dispatch_async(customQueue, ^{
        NSLog(@"任務(wù)E");
        sleep(1);
    });

總結(jié)完畢,有疑問(wèn),請(qǐng)留言

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 原文:http://www.cocoachina.com/ios/20170707/19769.html 本文主要...
    冬的天閱讀 2,420評(píng)論 0 12
  • 3.GCD GCD的全稱是Grand Central Dispatch,提供了非常多的純C語(yǔ)言的函數(shù) GCD的優(yōu)勢(shì)...
    Mario_ZJ閱讀 605評(píng)論 0 0
  • 目錄(GCD): 關(guān)鍵詞 混淆點(diǎn) 場(chǎng)景應(yīng)用 總結(jié) 1. 關(guān)鍵詞 線程概念: 獨(dú)立執(zhí)行的代碼段,一個(gè)線程同時(shí)間只能執(zhí)...
    Ryan___閱讀 1,374評(píng)論 0 3
  • 12.月1日 1.感恩宇宙恩典,讓我在家呆了一上午,讓自已與佛菩薩的對(duì)話,看到光就生喜悅!2,感恩宇宙恩典,祝?!?..
    洋姐書香閣閱讀 286評(píng)論 0 0
  • 每當(dāng)凌晨從樓梯道傳來(lái)上樓的聲響,我都不止一次地提醒自己,如果身處異鄉(xiāng)這樣辛苦卻沒(méi)有質(zhì)量地活著,我一定選擇回國(guó)。 房...
    小花fayer閱讀 277評(píng)論 4 1

友情鏈接更多精彩內(nèi)容