簡(jiǎn)介
GCD(Grand Central Dispatch)是由蘋果開發(fā)的一個(gè)多核編程的解決方案。iOS4.0+才能使用,GCD是基于C語(yǔ)言的,所以在多線程方面比NSThread, NSOperation高效很多。
用途
1,CGD多線程
2,GCD定時(shí)器
3,CGD連續(xù)調(diào)用n次
4,CGD單例的實(shí)現(xiàn)
5,CGD延遲調(diào)用
6,CGD任務(wù)組
7,CGD任務(wù)柵欄
詳細(xì)講解
1,CGD多線程
dispatch_async:異步調(diào)度:不會(huì)等待任務(wù)執(zhí)行完成。
dispatch_sync:同步調(diào)度:等待任務(wù)執(zhí)行完成才能繼續(xù)。
dispatch_get_main_queue( ) 獲得主線程隊(duì)列
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)獲得分線程隊(duì)列,DISPATCH_QUEUE_PRIORITY_DEFAULT為執(zhí)行優(yōu)先級(jí),這里為默認(rèn)優(yōu)先級(jí)
我們要在什么時(shí)候使用多線程呢?
首先我們要知道app默認(rèn)是在主線程中運(yùn)行,如果我們要執(zhí)行一些比較耗時(shí)的工作,比如請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù),在網(wǎng)絡(luò)不是很好,或者數(shù)據(jù)比較大的時(shí)候,沒(méi)有辦法立即完成動(dòng)作,在完成數(shù)據(jù)請(qǐng)求任務(wù)之前,主線程一直被占用,app則會(huì)無(wú)法響應(yīng)任何操作,嚴(yán)重影響用戶體驗(yàn),這時(shí)候我們就用到多線程,把耗時(shí)的操作全部扔到分線程里面去,防止阻塞主線程。
下面為一個(gè)網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求,首先進(jìn)入分線程,然后請(qǐng)求數(shù)據(jù)(耗時(shí)操作),當(dāng)數(shù)據(jù)請(qǐng)求成功時(shí),一定要回到主線程賦值刷新界面。
//進(jìn)入分線程
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//耗時(shí)操作
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://img3.douban.com/view/movie_poster_cover/lpst/public/p480747492.jpg"]];
//回到主線程刷新界面
dispatch_async(dispatch_get_main_queue( ), ^{
imageView.image = [UIImage imageWithData:data];
});
});
注意?。?!
大家在使用多線程的時(shí)候盡量使用異步調(diào)度dispatch_async,因?yàn)橥秸{(diào)度dispatch_sync如果注意不到有可能造成線程阻塞,也就是死鎖。
舉個(gè)栗子,下面為典型的死鎖,死鎖產(chǎn)生的原因是使用同步調(diào)度調(diào)用當(dāng)前線程(一般都是主線程)造成的。
NSLog(@"我肯定是可以執(zhí)行的");
//我要等NSLog(@"我要等dispatch_sync執(zhí)行完我在執(zhí)行");執(zhí)行完我在執(zhí)行
dispatch_sync(mainQueue, ^{
NSLog(@"我要等dispatch_sync執(zhí)行完我在執(zhí)行");
});
NSLog(@"前面線程堵住啦,我執(zhí)行不了");
大家思考下為什么異步調(diào)度不會(huì)造成死鎖?
2,GCD定時(shí)器
如果大家在使用定時(shí)器的時(shí)候,在滑動(dòng)屏幕的時(shí)候定時(shí)器會(huì)停止的話,是因?yàn)槎〞r(shí)器創(chuàng)建在了主線程,在創(chuàng)建timer的時(shí)候把最后一個(gè)參數(shù)改成dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),創(chuàng)建在分線程即可
//創(chuàng)建時(shí)間源
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
//設(shè)置時(shí)間源
/*
參數(shù)1:timer
參數(shù)2:時(shí)間間隔
參數(shù)3:時(shí)間誤差
*/
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0);
//執(zhí)行的任務(wù)
dispatch_source_set_event_handler(timer, ^{
NSLog(@"把要使用定時(shí)器執(zhí)行的代碼寫在這個(gè)block里");
});
//開啟定時(shí)器
dispatch_resume(timer);
//定時(shí)器銷毀
dispatch_cancel(timer);
注意?。?/strong>
定時(shí)器一定要記得手動(dòng)銷毀,不然會(huì)發(fā)生內(nèi)存泄漏。
3,CGD連續(xù)調(diào)用n次
dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t t) {
NSLog(@"xxxxx");
});
4,CGD單例的實(shí)現(xiàn)
//線程安全
static UIView *view = nil;
//該代碼只會(huì)執(zhí)行一次,一般用作單例
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
view = [[UIView alloc] initWithFrame:self.view.bounds];
});
5,CGD延遲調(diào)用
/*
參數(shù)1:開始計(jì)時(shí)時(shí)間,DISPATCH_TIME_NOW為現(xiàn)在開始計(jì)時(shí)
參數(shù)2:延遲時(shí)間,這里為三秒,可根據(jù)自己需求自行修改
參數(shù)3:執(zhí)行隊(duì)列,這里為主隊(duì)列
*/
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"代碼寫這里");
});
6,CGD任務(wù)組
在多線程中異步調(diào)度執(zhí)行任務(wù)時(shí),是沒(méi)有固定順序的,所有在異步調(diào)度下有一個(gè)任務(wù)需要最后執(zhí)行,則可以使用任務(wù)組。
//比如有3個(gè)任務(wù):A,B,C. A,B先異步執(zhí)行,最后執(zhí)行C
//創(chuàng)建隊(duì)列
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"A");
sleep(1);
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"B");
sleep(1);
});
//最后通知要執(zhí)行的任務(wù)
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"C");
sleep(1);
});
7,CGD任務(wù)柵欄
如上所述,異步調(diào)度執(zhí)行任務(wù)沒(méi)有固定順序,而柵欄把任務(wù)分開,先執(zhí)行柵欄之前的,再執(zhí)行柵欄之后的,下面例子AB任務(wù)順序不固定,DE任務(wù)順序不固定,但是AB一定在C之前執(zhí)行,DE在C之后執(zhí)行
//自定義隊(duì)列
/*
參數(shù)1:隊(duì)列名字
參數(shù)2:串行/并行
DISPATCH_QUEUE_SERIAL(串行隊(duì)列)/DISPATCH_QUEUE_CONCURRENT(并行隊(duì)列)
*/
dispatch_queue_t customQueue = dispatch_queue_create("customQueue", DISPATCH_QUEUE_CONCURRENT);
//先執(zhí)行AB
dispatch_async(customQueue, ^{
NSLog(@"任務(wù)A");
sleep(1);
});
dispatch_async(customQueue, ^{
NSLog(@"任務(wù)B");
sleep(1);
});
//障礙物,線程?hào)艡?執(zhí)行C
dispatch_barrier_async(customQueue, ^{
NSLog(@"任務(wù)C");
sleep(1);
});
//再執(zhí)行DE
dispatch_async(customQueue, ^{
NSLog(@"任務(wù)D");
sleep(1);
});
dispatch_async(customQueue, ^{
NSLog(@"任務(wù)E");
sleep(1);
});
總結(jié)完畢,有疑問(wèn),請(qǐng)留言