玩轉iOS開發:iOS中的GCD開發(三)

文章分享至個人我的技術博客: https://cainluo.github.io/15019284409430.htmlhtml


上一章, 咱們瞭解到了GCD裏的一些隊列和任務的知識, 也實踐了一下, 同時咱們也對主隊列的一些小狀況瞭解了一下, 好比上一章講到的卡線程的問題, 若是沒有看的朋友能夠去看看玩轉iOS開發:iOS中的GCD開發(二)回顧一下.git

這一章, 咱們來說講關於GCD的一些其餘小知識.github

轉載聲明:如須要轉載該文章, 請聯繫做者, 而且註明出處, 以及不能擅自修改本文.vim


GCD之間的通訊

在咱們平常的iOS開發裏, 咱們通常是會在主線程裏刷新UI, 好比: 處理按鈕的點擊事件, 滾動視圖, 拖拽視圖等等操做.安全

但其餘比較耗時的, 咱們都會放在其餘線程裏進行操做, 好比: 上傳/下載圖片, 上傳/下載文件等比較耗時的操做.微信

但這裏還須要配合一下主線程來進行操做一番, 好比咱們下載完圖片以後, 須要回到主線程中刷新UI, 這時候咱們就須要用到GCD之間的通訊啦.app

不懂? 那咱們就來看看代碼唄, 這裏爲了和上一章的工程重複, 我就新建過另外一個工程, 取名爲GCD-Up-Example, 機智如我~異步

- (void)gcdCommunication {
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        for (NSInteger i = 0; i < 5; i++) {
            
            NSLog(@"第%ld次任務的主線程爲: %@", i, [NSThread currentThread]);
        }
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            NSLog(@"回到主線程, 該線程爲: %@", [NSThread currentThread]);
        });
    });
}
複製代碼
2017-08-05 18:47:11.942 GCD-Up-Example[15176:7745714] 第0次任務的主線程爲: <NSThread: 0x60000006bb80>{number = 3, name = (null)}
2017-08-05 18:47:11.942 GCD-Up-Example[15176:7745714] 第1次任務的主線程爲: <NSThread: 0x60000006bb80>{number = 3, name = (null)}
2017-08-05 18:47:11.943 GCD-Up-Example[15176:7745714] 第2次任務的主線程爲: <NSThread: 0x60000006bb80>{number = 3, name = (null)}
2017-08-05 18:47:11.943 GCD-Up-Example[15176:7745714] 第3次任務的主線程爲: <NSThread: 0x60000006bb80>{number = 3, name = (null)}
2017-08-05 18:47:11.944 GCD-Up-Example[15176:7745714] 第4次任務的主線程爲: <NSThread: 0x60000006bb80>{number = 3, name = (null)}
2017-08-05 18:47:11.948 GCD-Up-Example[15176:7745541] 回到主線程, 該線程爲: <NSThread: 0x60000006a1c0>{number = 1, name = main}
複製代碼
  • 從結果裏, 咱們能夠看到, 全部任務執行完以後, 就會回到主線程裏了.

GCD的柵欄方法

有這麼一個場景, 當咱們須要進行異步操做兩組數據時, 要求執行完第一組以後, 才能執行第二組, 那這個咋辦咧?async

GCD當中, 有一個方法能夠解決這種需求, 也就是所謂的柵欄方法也稱爲屏障, 如今咱們來擼一下:學習

- (void)gcdBarrier {
    
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        
        NSLog(@"第一次任務的主線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"第二次任務的主線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_barrier_async(queue, ^{
        
        NSLog(@"第一次任務, 第二次任務執行完畢, 繼續執行");
    });

    dispatch_async(queue, ^{
        
        NSLog(@"第三次任務的主線程爲: %@", [NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        
        NSLog(@"第四次任務的主線程爲: %@", [NSThread currentThread]);
    });
}
複製代碼
2017-08-05 19:00:44.494 GCD-Up-Example[15252:7757142] 第一次任務的主線程爲: <NSThread: 0x60000007d580>{number = 3, name = (null)}
2017-08-05 19:00:44.494 GCD-Up-Example[15252:7757144] 第二次任務的主線程爲: <NSThread: 0x60800007bb00>{number = 4, name = (null)}
2017-08-05 19:00:44.494 GCD-Up-Example[15252:7757144] 第一次任務, 第二次任務執行完畢, 繼續執行
2017-08-05 19:00:44.495 GCD-Up-Example[15252:7757144] 第三次任務的主線程爲: <NSThread: 0x60800007bb00>{number = 4, name = (null)}
2017-08-05 19:00:44.495 GCD-Up-Example[15252:7757142] 第四次任務的主線程爲: <NSThread: 0x60000007d580>{number = 3, name = (null)}
複製代碼
  • 經過結果, 咱們能夠看出, 在執行完第一次和第二次任務後, 會停留一下, 執行完這個柵欄方法以後, 纔會繼續執行以後的任務.

GCD的延遲方法

有時候, 須要一些延遲操做的場景, 那咋辦咧? 放心~GCD也有提供這樣子的方法, 而且延遲多少時間是由你說了算:

- (void)gcdAfter {
    
    NSLog(@"我是一個路人");
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        NSLog(@"2秒後執行了.");
    });
}
複製代碼
2017-08-05 19:07:20.039 GCD-Up-Example[15340:7766123] 我是一個路人
2017-08-05 19:07:22.225 GCD-Up-Example[15340:7766123] 2秒後執行了.
複製代碼
  • 看到結果, 咱們就知道, 的確是延遲了兩秒後才執行.
  • 若是大家不知道在哪裏設置時間的話, 看這句代碼裏的2.0, 這就是設置時間了.

GCD只執行一次的方法

有時候, 咱們須要建立一個類, 而這個類的某個方法只能夠執行一次, 好比建立一個單例, 怎麼用GCD解決呢?

既然可以提到這個問題, 那GCD確定也會提供對方的方法嘛, 是吧~

- (void)gcdOne {
    
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        // 這裏寫只執行一次的任務就行了, 默認是線程安全, 因此不用擔憂
    });
}
複製代碼

GCD的快速遍歷方法

GCD當中, 也有一個相似for的遍歷方法, 和for不一樣, 它幾乎是同時遍歷的.

- (void)gcdApply {
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_apply(5, queue, ^(size_t index) {
        
        NSLog(@"執行第%ld任務, 當前線程爲: %@", index, [NSThread currentThread]);
    });
}
複製代碼
2017-08-05 20:36:08.389 GCD-Up-Example[15555:7794146] 執行第0任務, 當前線程爲: <NSThread: 0x608000074840>{number = 1, name = main}
2017-08-05 20:36:08.389 GCD-Up-Example[15555:7794186] 執行第1任務, 當前線程爲: <NSThread: 0x60800007e2c0>{number = 3, name = (null)}
2017-08-05 20:36:08.389 GCD-Up-Example[15555:7794184] 執行第2任務, 當前線程爲: <NSThread: 0x60800007e200>{number = 4, name = (null)}
2017-08-05 20:36:08.389 GCD-Up-Example[15555:7794183] 執行第3任務, 當前線程爲: <NSThread: 0x60800007e300>{number = 5, name = (null)}
2017-08-05 20:36:08.389 GCD-Up-Example[15555:7794146] 執行第4任務, 當前線程爲: <NSThread: 0x608000074840>{number = 1, name = main}
複製代碼
  • 從結果裏咱們能夠看到, 它幾乎是同時遍歷的, 並且要注意, 這個方法是開啓了新線程來進行遍歷的.

GCD的Queue Group

在某個場景下, 咱們須要同時異步執行兩個耗時的任務, 而且在執行完成後直接回到主線程, 這個怎麼作呢?

GCD中, 有一個叫作隊列組的東西(Queue Group), 它就能夠知足咱們這個場景需求了.

- (void)gcdQueueGroup {
    
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_group_async(group,
                         queue,
                         ^{
                             // 執行第一個耗時的任務
                         });
    
    dispatch_group_async(group,
                         queue,
                         ^{
                             // 執行第二個耗時的任務
                         });
    
    dispatch_group_notify(group,
                          dispatch_get_main_queue(),
                          ^{
                              // 回到主線程
                          });
}
複製代碼

總結

GCD的一些經常使用知識基本到這裏, 基本上已經哦了, 若是你還要更深刻的去了解的話, 能夠去GCD官方文檔裏查找一下你所須要的資料.

再多說一句話, 學習理論知識當然重要, 但要和實際開發使用掛鉤, 否則光學不用, 等於空.


工程地址

項目地址: https://github.com/CainRun/iOS-Project-Example/tree/master/GCD-Up-Example


最後

碼字很費腦, 看官賞點飯錢可好

微信

支付寶
相關文章
相關標籤/搜索