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

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


在前面一篇文章裏, 咱們大概知道了GCD是個什麼概念, 也知道了如何建立隊列, 建立任務, 但前面的都只是理念, 估計有不少人不喜, 要開始噴我了, 這才咱們來用代碼實踐實踐, 若是沒有看過上一篇的, 能夠去玩轉iOS開發:iOS中的GCD開發(一)看看.git

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


CGD的基本使用

這裏咱們就須要建立一個工程, 而後試試水:vim

並行隊列+同步執行

- (void)syncQueueConcurrent {
    
    NSLog(@"開始執行任務");
    
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_sync(queue, ^{
        
        NSLog(@"第一個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        
        NSLog(@"第二個任務當前線程爲: %@", [NSThread currentThread]);
    });

    dispatch_sync(queue, ^{
        
        NSLog(@"第三個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    NSLog(@"結束執行任務");
}
複製代碼
2017-08-05 15:03:55.567 GCD-Example[14007:7612071] 開始執行任務
2017-08-05 15:03:55.567 GCD-Example[14007:7612071] 第一個任務當前線程爲: <NSThread: 0x608000067340>{number = 1, name = main}
2017-08-05 15:03:55.567 GCD-Example[14007:7612071] 第二個任務當前線程爲: <NSThread: 0x608000067340>{number = 1, name = main}
2017-08-05 15:03:55.568 GCD-Example[14007:7612071] 第三個任務當前線程爲: <NSThread: 0x608000067340>{number = 1, name = main}
2017-08-05 15:03:55.568 GCD-Example[14007:7612071] 結束執行任務
複製代碼
  • 從輸出結果, 咱們能夠看得出, 如今當前的線程都爲同一條, 名爲main, 並且線程數只有1.
  • 在執行任務的前和執行任務後, 我都加了一個Log, 從執行順序上咱們能夠知道, 並行隊列+同步執行是一個任務一個任務的去執行的.

並行隊列+異步執行

接下來咱們看看並行隊列+異步執行的組合:bash

- (void)asyncQueueConcurrent {
    
    NSLog(@"開始執行任務");
    
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        
        NSLog(@"第一個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"第二個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"第三個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    NSLog(@"結束執行任務");
}
複製代碼
2017-08-05 15:08:40.069 GCD-Example[14052:7619255] 開始執行任務
2017-08-05 15:08:40.070 GCD-Example[14052:7619255] 結束執行任務
2017-08-05 15:08:40.070 GCD-Example[14052:7619380] 第三個任務當前線程爲: <NSThread: 0x60800026a640>{number = 5, name = (null)}
2017-08-05 15:08:40.070 GCD-Example[14052:7619363] 第一個任務當前線程爲: <NSThread: 0x60800026a5c0>{number = 3, name = (null)}
2017-08-05 15:08:40.070 GCD-Example[14052:7619362] 第二個任務當前線程爲: <NSThread: 0x60000026bb00>{number = 4, name = (null)}
複製代碼
  • 從輸出的結果, 咱們能夠看到, 這裏的線程數有好幾條, 並且線程的名字也不知道, 而且從時間上來看到, 幾乎都是在同一時間執行任務的.
  • 因此咱們能夠得出一個結果, 並行隊列+異步執行的組合除了在主隊列上執行, 還會另外開啓多幾條線程來並行執行任務.

串行隊列+同步執行

繼續下一個串行隊列+同步執行組合:微信

- (void)syncQueueSerial {
    
    NSLog(@"開始執行任務");

    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(queue, ^{
        
        NSLog(@"第一個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        
        NSLog(@"第二個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        
        NSLog(@"第三個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    NSLog(@"結束執行任務");
}
複製代碼
2017-08-05 15:16:21.723 GCD-Example[14119:7628753] 開始執行任務
2017-08-05 15:16:21.723 GCD-Example[14119:7628753] 第一個任務當前線程爲: <NSThread: 0x6080000794c0>{number = 1, name = main}
2017-08-05 15:16:21.724 GCD-Example[14119:7628753] 第二個任務當前線程爲: <NSThread: 0x6080000794c0>{number = 1, name = main}
2017-08-05 15:16:21.724 GCD-Example[14119:7628753] 第三個任務當前線程爲: <NSThread: 0x6080000794c0>{number = 1, name = main}
2017-08-05 15:16:21.724 GCD-Example[14119:7628753] 結束執行任務
複製代碼
  • 從結果看, 這個串行隊列+同步執行組合是一個一個任務來執行的, 都是在主隊列中完成, 並無開啓新線程.
  • 因爲是串行隊列, 因此咱們能夠在上面看到, 先執行第一個開始Log, 而後任務都是按個添加, 最後在執行結束Log.

串行隊列 + 異步執行

繼續串行隊列 + 異步執行:異步

- (void)asyncQueueSerial {
    
    NSLog(@"開始執行任務");
    
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{
        
        NSLog(@"第一個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"第二個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"第三個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    NSLog(@"結束執行任務");
}
複製代碼
2017-08-05 17:32:06.723 GCD-Example[14279:7669095] 開始執行任務
2017-08-05 17:32:06.723 GCD-Example[14279:7669095] 結束執行任務
2017-08-05 17:32:06.723 GCD-Example[14279:7669192] 第一個任務當前線程爲: <NSThread: 0x60800006ee00>{number = 3, name = (null)}
2017-08-05 17:32:06.724 GCD-Example[14279:7669192] 第二個任務當前線程爲: <NSThread: 0x60800006ee00>{number = 3, name = (null)}
2017-08-05 17:32:06.724 GCD-Example[14279:7669192] 第三個任務當前線程爲: <NSThread: 0x60800006ee00>{number = 3, name = (null)}
複製代碼
  • 從結果來看, 咱們能夠看到, 是開啓新線程來執行任務, 但因爲是串行隊列, 因此這裏的任務仍是一個接着一個來執行的.
  • 另外, 這裏還有一點, 咱們能夠看到先打印了開發Log和結束Log, 最後才執行任務, 能夠說明, 這裏的任務並非一會兒就開始執行的, 是須要將任務都添加到隊列裏, 而後纔開始同步執行.

主隊列

主隊列是GCD自帶的一種特殊的隊列, 這裏有兩點須要注意一下:async

  • 全部放在主隊列裏執行的任務都會放到主線程裏執行.
  • 咱們能夠經過dispatch_get_main_queue()獲取主隊列.

說那麼多不如直接來段代碼:ui

主隊列+同步執行

- (void)syncMainQueue {
    
    NSLog(@"開始執行任務");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_sync(queue, ^{
        
        NSLog(@"第一個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        
        NSLog(@"第二個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        
        NSLog(@"第三個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    NSLog(@"結束執行任務");
}
複製代碼
2017-08-05 17:56:24.607 GCD-Example[14437:7689741] 開始執行任務
複製代碼

當咱們運行的時候發現異常了, 斷言在執行完開始Log以後不動了, 爲何咧?spa

其實這是由於咱們在ViewDidload方法裏執行了[self syncMainQueue];方法, 咱們都知道, 同步執行是一個一個任務去執行的.

但主線還在執行[self syncMainQueue];的時候, 咱們又往主線程裏塞任務, 這個時候就會出現異常現象, 咱們稱之爲卡線程.

若是要解決的話, 咱們就須要在ViewDidload裏改善一下方案:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        
        [self syncMainQueue];
    });
}
複製代碼
2017-08-05 18:03:33.209 GCD-Example[14492:7698292] 開始執行任務
2017-08-05 18:03:33.214 GCD-Example[14492:7698172] 第一個任務當前線程爲: <NSThread: 0x600000066340>{number = 1, name = main}
2017-08-05 18:03:33.215 GCD-Example[14492:7698172] 第二個任務當前線程爲: <NSThread: 0x600000066340>{number = 1, name = main}
2017-08-05 18:03:33.216 GCD-Example[14492:7698172] 第三個任務當前線程爲: <NSThread: 0x600000066340>{number = 1, name = main}
2017-08-05 18:03:33.216 GCD-Example[14492:7698292] 結束執行任務
複製代碼

唔, 醬紫改造就能夠順利的執行完任務了, 這裏還須要提多兩點:

  • 在執行的結果裏, 雖咱們在ViewDidload用的是並行+異步的組合去改善的, 但這不會影響到主隊列裏的任務執行順序, 也不會開啓新線程.
  • 主隊列是屬於串行隊列, 因此咱們能夠看到所執行的任務是一個接着一個.

主隊列+異步執行

最後一個組合主隊列+異步執行:

- (void)asyncMainQueue {
    
    NSLog(@"開始執行任務");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
        
        NSLog(@"第一個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"第二個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"第三個任務當前線程爲: %@", [NSThread currentThread]);
    });
    
    NSLog(@"結束執行任務");
}
複製代碼
2017-08-05 18:08:16.059 GCD-Example[14537:7704614] 開始執行任務
2017-08-05 18:08:16.059 GCD-Example[14537:7704614] 結束執行任務
2017-08-05 18:08:16.064 GCD-Example[14537:7704614] 第一個任務當前線程爲: <NSThread: 0x608000261700>{number = 1, name = main}
2017-08-05 18:08:16.064 GCD-Example[14537:7704614] 第二個任務當前線程爲: <NSThread: 0x608000261700>{number = 1, name = main}
2017-08-05 18:08:16.065 GCD-Example[14537:7704614] 第三個任務當前線程爲: <NSThread: 0x608000261700>{number = 1, name = main}
複製代碼
  • 從結果上咱們能夠看到, 雖然咱們用的是異步執行, 具有了開啓新線程的能力, 可是因爲這是主隊列, 因此全部的任務都是在主線程中, 任務也是一個接着一個執行的.
  • 另外, 咱們能夠看到, 是先執行開始Log, 結束Log, 最後再執行主隊列裏的任務, 這裏咱們就能夠知道, 任務並非立刻就執行的, 而是把全部任務都添加到隊列裏以後, 再執行.

總結

學完以後, 咱們就能夠愉快的和GCD玩耍了, 隊列, 任務神馬的, 不再用擔憂了.


工程地址

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


最後

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

微信

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