本文的主要內(nèi)容是:
- 什么是GCD
- 了解GCD前侧馅,需要了解的基礎(chǔ)知識(shí)
- GCD的使用
- 使用注意事項(xiàng)
-GCD學(xué)習(xí)前鋪墊-
什么是GCD
- GCD (Grand Central Dispatch) 是Apple公司開發(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ù)昨稼,我們打印了一下log
4.任務(wù)被執(zhí)行:
異步執(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";
});