什么是GCD
了解GCD前往堡,需要了解的基礎(chǔ)知識(shí)
GCD的使用
使用注意事項(xiàng)
-GCD學(xué)習(xí)前鋪墊-
什么是GCD
GCD (Grand Central Dispatch) 是Apple公司開(kāi)發(fā)的一種技術(shù),它旨在優(yōu)化多核環(huán)境中的并發(fā)操作并取代傳統(tǒng)多線程的編程模式
GCD是基于C語(yǔ)言的線程管理方案按摘,使用者無(wú)需過(guò)多參與線程的管理枚驻,只需要將想要執(zhí)行的代碼濒旦,添加到想要添加的調(diào)度隊(duì)列即可
在Mac OS X 10.6雪豹中首次推出,并在iOS4.0中引入到了iOS
GCD主要用在后臺(tái)執(zhí)行較慢任務(wù)再登;延遲執(zhí)行任務(wù)尔邓;以及在后臺(tái)任務(wù)中,切換回主線程锉矢,更新UI
iOS中常用的其它多線程技術(shù)
pthread:通用于Unix/Linux/Windows的C語(yǔ)言線程管理API梯嗽,可移植性強(qiáng),但是使用繁瑣沽损,需要使用者管理線程生命周期
NSThread:使用Objective-C實(shí)現(xiàn)灯节,輕量級(jí)的線程管理,但是也需要手動(dòng)管理線程的生命周期
NSOperation:基于GCD绵估,使用Objective-C實(shí)現(xiàn)的面向?qū)ο蟮木€程管理炎疆,比GCD更高級(jí),但是處理簡(jiǎn)單任務(wù)會(huì)比GCD代碼更多
總之国裳,iOS里GCD用的很多
GCD知識(shí)鋪墊
競(jìng)爭(zhēng)&同步:兩個(gè)線程搶奪同一個(gè)資源形入,就會(huì)競(jìng)爭(zhēng),為了防止競(jìng)爭(zhēng)缝左,一個(gè)線程擁有資源的時(shí)候亿遂,會(huì)對(duì)資源加鎖螟蒸,另一個(gè)線程就要等待解鎖以后再擁有這個(gè)資源,這叫同步崩掘。
死鎖:兩個(gè)線程互相等待對(duì)方釋放資源
主線程&后臺(tái)線程:主線程也叫前臺(tái)線程七嫌,程序啟動(dòng)的默認(rèn)線程,操作UI的線程苞慢。后臺(tái)線程诵原,即非主線程,用于不影響主線程的完成一些任務(wù)
并行&串行:并行挽放,就是幾個(gè)任務(wù)一起完成绍赛。串行,就是幾個(gè)任務(wù)一個(gè)接著一個(gè)完成辑畦。
同步&異步:同步執(zhí)行線程吗蚌,等待新線程執(zhí)行完以后,再繼續(xù)執(zhí)行當(dāng)前線程纯出,很少用到蚯妇。異步執(zhí)行線程,在執(zhí)行新線程的同時(shí)暂筝,繼續(xù)執(zhí)行當(dāng)前線程箩言,常用。
-GCD的使用-
GCD的使用步驟
創(chuàng)建線程隊(duì)列:主隊(duì)列焕襟,全局并行隊(duì)列陨收,手動(dòng)創(chuàng)建串行隊(duì)列
選擇執(zhí)行方式:同步(較少使用),異步鸵赖,延時(shí)
添加需要執(zhí)行的任務(wù):也就是想要?jiǎng)?chuàng)建隊(duì)列做什么务漩,以Block塊語(yǔ)句形式創(chuàng)建
任務(wù)被執(zhí)行:Block按照設(shè)計(jì)被執(zhí)行
舉例
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"我在五秒后打印"); }); NSLog(@"線程被部署");
這段代碼的原型如下
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
首先,創(chuàng)建線程隊(duì)列它褪,本例中我們使用主隊(duì)列饵骨,所以直接使用dispatch_get_main_queue()
然后,選擇執(zhí)行方式列赎,本例使用延時(shí)方法dispatch_after
添加需要執(zhí)行的任務(wù)宏悦,我們打印了一下log4.任務(wù)被執(zhí)行:
log
異步執(zhí)行線程
異步后臺(tái)線程
主要用途:執(zhí)行較慢的任務(wù),例如大量計(jì)算包吝,網(wǎng)絡(luò)請(qǐng)求等
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"在異步并行隊(duì)列中執(zhí)行"); }); dispatch_queue_t queue = dispatch_queue_create("com.realank.GCDDemo.myQueue", NULL); dispatch_async(queue, ^{ NSLog(@"在異步串行隊(duì)列中執(zhí)行"); });
上面的代碼饼煞,分別創(chuàng)建了一個(gè)異步后臺(tái)并行線程和一個(gè)自創(chuàng)建的異步后臺(tái)串行線程。
異步主線程
主要用途:用于在后臺(tái)線程的任務(wù)將要完成時(shí)诗越,切換到主線程更新UI
dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"在異步主線程中執(zhí)行"); });
同步執(zhí)行線程
同步后臺(tái)線程
主要用途:在新線程中執(zhí)行任務(wù)砖瞧,并且等待線程執(zhí)行完畢再向后執(zhí)行,幾乎不用
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"在同步并行隊(duì)列中執(zhí)行"); }); dispatch_queue_t queue = dispatch_queue_create("com.realank.GCDDemo.myQueue", NULL); dispatch_sync(queue, ^{ NSLog(@"在同步串行隊(duì)列中執(zhí)行"); });
上面的代碼嚷狞,分別創(chuàng)建了一個(gè)異步后臺(tái)并行線程和一個(gè)自創(chuàng)建的異步后臺(tái)串行線程块促。
同步主線程(慎用)
主要用途:只有在其它線程中才可能執(zhí)行此方法荣堰,否則會(huì)死鎖
dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@“在同步主線程中執(zhí)行,慎用竭翠,否則會(huì)死鎖”); });
延時(shí)執(zhí)行線程
主要用途:用于等待一段時(shí)間以后再執(zhí)行的任務(wù)
dispatch_queue_t queue = dispatch_get_main_queue();// 也可以使用其它線程// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);// dispatch_queue_t queue = dispatch_queue_create("com.realank.GCDDemo.myQueue2", NULL); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), queue, ^{ NSLog(@"延時(shí)2秒執(zhí)行"); }); NSLog(@"延時(shí)線程已部署");
-GCD的總結(jié)-
創(chuàng)建線程隊(duì)列
主隊(duì)列:
dispatch_queue_t queue = dispatch_get_main_queue();
全局并行隊(duì)列:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
手動(dòng)創(chuàng)建串行隊(duì)列:
dispatch_queue_t queue = dispatch_queue_create("com.realank.GCDDemo.myQueue", NULL);
線程執(zhí)行方式
異步:
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
同步(慎用):
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
延時(shí):
```void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);```
關(guān)于循環(huán)強(qiáng)引用
在block中使用self振坚,或者使用屬性(會(huì)隱含調(diào)用self),會(huì)讓block持有其類實(shí)例斋扰,如果此時(shí)block渡八,又被存儲(chǔ)為類實(shí)例的copy或strong屬性,就會(huì)造成循環(huán)強(qiáng)引用传货。在GCD的block使用中屎鳍,不會(huì)造成類實(shí)例對(duì)block的引用,但是為了以防萬(wàn)一问裕,我習(xí)慣在Block中統(tǒng)一使用weakSelf來(lái)引用屬性或方法逮壁。
__weak __typeof(self) weakSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ weakSelf.string = @“hello"; });