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沒執行完,就開始執行後面的操作了。
雖然說多執行緒在開發和麵試中都被認為是重中之重,但是就實際開發過程中而言,用到的場景並沒有提供的方法多,沒必要死扣理論和知道的方法多少,會用來解決問題才是最重要的!