1. 程式人生 > >GCD常用方法及應用場景

GCD常用方法及應用場景

開發過程中,出現耗時操作造成介面卡頓是常見的問題之一,問題原因就是因為耗時操作阻塞了主執行緒,所以要解決這類問題最簡單的就是引進子執行緒,將耗時操作移出主執行緒,耗時操作完成後回到主執行緒中更新UI。
之前在做一個通訊錄的時候,由於需要自己進行排序,所以第一次時需要將幾千條的資料都拉下來然後處理,這是非常耗時的,直接放在主執行緒中網路請求然後各種處理資料會讓介面卡死3到5秒。後來使用GCD的併發佇列非同步處理解決了,個人感覺非常的簡單實用,關鍵程式碼如下:

dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async
(queue, ^{ //耗時操作,如網路請求 //請求完成之後,回到主執行緒更新UI dispatch_async(dispatch_get_main_queue(), ^{ //更新UI操作 }); });

建議在開發過程中,頁面的網路請求和耗時操作都可以以這種方式處理,一般每個頁面的網路請求不會太多,不會造成併發數太大的問題,這也是使用者體驗和效能優化的一種,網路再慢也不會給使用者帶來卡頓的體驗。
還有比較複雜一點的頁面,可能存在多個操作,而某個操作依賴前幾個操作完成之後才能開始,這個時候我們可以使用GCD的執行緒組,使用程式碼:

dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(group, queue, ^{
       //操作一
        for (int i = 0; i < 10; i ++) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_group_async(group, queue, ^{
        //操作二
for (int i = 0; i < 10; i ++) { NSLog(@"2------%@",[NSThread currentThread]); } }); dispatch_group_async(group, queue, ^{ //操作三 for (int i = 0; i < 10; i ++) { NSLog(@"3------%@",[NSThread currentThread]); } }); dispatch_group_notify(group, queue, ^{ //最後的操作 for (int i = 0; i < 10; i ++) { NSLog(@"notify------%@",[NSThread currentThread]); } });

我們先來看一下列印結果:

2018-08-30 15:04:19.178991+0800 GCD_demo[3996:227745] 1------<NSThread: 0x604000261d00>{number = 3, name = (null)}
2018-08-30 15:04:19.178995+0800 GCD_demo[3996:227743] 3------<NSThread: 0x60c00007d080>{number = 5, name = (null)}
2018-08-30 15:04:19.179000+0800 GCD_demo[3996:227746] 2------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.179238+0800 GCD_demo[3996:227743] 3------<NSThread: 0x60c00007d080>{number = 5, name = (null)}
2018-08-30 15:04:19.179240+0800 GCD_demo[3996:227745] 1------<NSThread: 0x604000261d00>{number = 3, name = (null)}
2018-08-30 15:04:19.179243+0800 GCD_demo[3996:227746] 2------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.179668+0800 GCD_demo[3996:227743] 3------<NSThread: 0x60c00007d080>{number = 5, name = (null)}
2018-08-30 15:04:19.179910+0800 GCD_demo[3996:227745] 1------<NSThread: 0x604000261d00>{number = 3, name = (null)}
2018-08-30 15:04:19.179940+0800 GCD_demo[3996:227746] 2------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.179983+0800 GCD_demo[3996:227743] 3------<NSThread: 0x60c00007d080>{number = 5, name = (null)}
2018-08-30 15:04:19.180011+0800 GCD_demo[3996:227745] 1------<NSThread: 0x604000261d00>{number = 3, name = (null)}
2018-08-30 15:04:19.180341+0800 GCD_demo[3996:227746] 2------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.180595+0800 GCD_demo[3996:227745] 1------<NSThread: 0x604000261d00>{number = 3, name = (null)}
2018-08-30 15:04:19.180753+0800 GCD_demo[3996:227743] 3------<NSThread: 0x60c00007d080>{number = 5, name = (null)}
2018-08-30 15:04:19.180920+0800 GCD_demo[3996:227746] 2------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.181272+0800 GCD_demo[3996:227745] 1------<NSThread: 0x604000261d00>{number = 3, name = (null)}
2018-08-30 15:04:19.181380+0800 GCD_demo[3996:227743] 3------<NSThread: 0x60c00007d080>{number = 5, name = (null)}
2018-08-30 15:04:19.181513+0800 GCD_demo[3996:227746] 2------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.181807+0800 GCD_demo[3996:227745] 1------<NSThread: 0x604000261d00>{number = 3, name = (null)}
2018-08-30 15:04:19.181906+0800 GCD_demo[3996:227743] 3------<NSThread: 0x60c00007d080>{number = 5, name = (null)}
2018-08-30 15:04:19.182027+0800 GCD_demo[3996:227746] 2------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.182437+0800 GCD_demo[3996:227745] 1------<NSThread: 0x604000261d00>{number = 3, name = (null)}
2018-08-30 15:04:19.182531+0800 GCD_demo[3996:227743] 3------<NSThread: 0x60c00007d080>{number = 5, name = (null)}
2018-08-30 15:04:19.182616+0800 GCD_demo[3996:227746] 2------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.182765+0800 GCD_demo[3996:227745] 1------<NSThread: 0x604000261d00>{number = 3, name = (null)}
2018-08-30 15:04:19.183371+0800 GCD_demo[3996:227743] 3------<NSThread: 0x60c00007d080>{number = 5, name = (null)}
2018-08-30 15:04:19.183427+0800 GCD_demo[3996:227746] 2------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.183489+0800 GCD_demo[3996:227745] 1------<NSThread: 0x604000261d00>{number = 3, name = (null)}
2018-08-30 15:04:19.183509+0800 GCD_demo[3996:227743] 3------<NSThread: 0x60c00007d080>{number = 5, name = (null)}
2018-08-30 15:04:19.183644+0800 GCD_demo[3996:227746] 2------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.184220+0800 GCD_demo[3996:227746] notify------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.184694+0800 GCD_demo[3996:227746] notify------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.185670+0800 GCD_demo[3996:227746] notify------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.186316+0800 GCD_demo[3996:227746] notify------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.186535+0800 GCD_demo[3996:227746] notify------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.186660+0800 GCD_demo[3996:227746] notify------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.187406+0800 GCD_demo[3996:227746] notify------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.187940+0800 GCD_demo[3996:227746] notify------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.188188+0800 GCD_demo[3996:227746] notify------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}
2018-08-30 15:04:19.188589+0800 GCD_demo[3996:227746] notify------<NSThread: 0x60800027f0c0>{number = 4, name = (null)}

我們會發現,操作一、操作二和操作三是無序執行的,但是最後的操作是等前面的都執行完成之後才開始執行的。像這樣的應用場景還是很多的,比如第三個網路請求的引數依賴於前兩個網路請求的結果,就可以用這種方式來處理。
如果想要操作一、二、三也都順序執行,可以使用序列佇列。還可以使用enter和leave方法,用法如下:

dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
       //操作一
        NSLog(@"111");
        dispatch_group_leave(group);
    });
    dispatch_group_async(group, queue, ^{
        //操作二
        NSLog(@"222");

    });
    dispatch_group_async(group, queue, ^{
        //操作三
        NSLog(@"333");

    });
    dispatch_group_notify(group, queue, ^{
        //最後的操作
        for (int i = 0; i < 10; i ++) {
            NSLog(@"notify------%@",[NSThread currentThread]);
        }
    });

列印結果:

2018-08-30 15:34:01.152524+0800 GCD_demo[4391:254500] 111
2018-08-30 15:34:01.152530+0800 GCD_demo[4391:254497] 333
2018-08-30 15:34:01.152524+0800 GCD_demo[4391:254498] 222
2018-08-30 15:34:01.152854+0800 GCD_demo[4391:254498] notify------<NSThread: 0x60c00027c900>{number = 3, name = (null)}
2018-08-30 15:34:01.153542+0800 GCD_demo[4391:254498] notify------<NSThread: 0x60c00027c900>{number = 3, name = (null)}
2018-08-30 15:34:01.153710+0800 GCD_demo[4391:254498] notify------<NSThread: 0x60c00027c900>{number = 3, name = (null)}
2018-08-30 15:34:01.153855+0800 GCD_demo[4391:254498] notify------<NSThread: 0x60c00027c900>{number = 3, name = (null)}
2018-08-30 15:34:01.154183+0800 GCD_demo[4391:254498] notify------<NSThread: 0x60c00027c900>{number = 3, name = (null)}
2018-08-30 15:34:01.154307+0800 GCD_demo[4391:254498] notify------<NSThread: 0x60c00027c900>{number = 3, name = (null)}
2018-08-30 15:34:01.154711+0800 GCD_demo[4391:254498] notify------<NSThread: 0x60c00027c900>{number = 3, name = (null)}
2018-08-30 15:34:01.154830+0800 GCD_demo[4391:254498] notify------<NSThread: 0x60c00027c900>{number = 3, name = (null)}
2018-08-30 15:34:01.154944+0800 GCD_demo[4391:254498] notify------<NSThread: 0x60c00027c900>{number = 3, name = (null)}
2018-08-30 15:34:01.155039+0800 GCD_demo[4391:254498] notify------<NSThread: 0x60c00027c900>{number = 3, name = (null)}

以上程式碼可以保證操作一執行完才開始操作二和操作三,需要注意的一點是enter和leave方法是成對出現的,如果用了enter,沒有寫leave的話,會造成notify無法執行。如果操作一、二、三種存在block程式碼,那麼leave方法需要放在block中,否則block沒執行完,就開始執行後面的操作了。
雖然說多執行緒在開發和麵試中都被認為是重中之重,但是就實際開發過程中而言,用到的場景並沒有提供的方法多,沒必要死扣理論和知道的方法多少,會用來解決問題才是最重要的!