有時(shí)候我們在開發(fā)過程中,會有這樣的需求蓖租,a任務(wù)開始執(zhí)行的前提是b任務(wù)執(zhí)行完成,c任務(wù)開始執(zhí)行需要等a稻艰、b兩個(gè)異步任務(wù)完成涯鲁,即a依賴于b同木,c又依賴a,這種需求我們可以使用的GCD來處理黍氮。
//創(chuàng)建分組
dispatch_group_t group =dispatch_group_create();
//創(chuàng)建隊(duì)列
dispatch_queue_t queue =dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);
//往分組中添加任務(wù)
dispatch_group_async(group, queue, ^{
[NSThreadsleepForTimeInterval:2];//模擬耗時(shí)操作
NSLog(@"11111 %@", [NSThreadcurrentThread]);
});
//往分組中添加任務(wù)
dispatch_group_async(group, queue, ^{
[NSThreadsleepForTimeInterval:1];//模擬耗時(shí)操作
NSLog(@"2222 %@", [NSThreadcurrentThread]);
});
//分組中任務(wù)完成以后通知該block執(zhí)行
dispatch_group_notify(group, queue, ^{
NSLog(@"完成 %@", [NSThreadcurrentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"通知主線程刷新UI %@", [NSThreadcurrentThread]);
});
});
執(zhí)行結(jié)果:
2017-10-24 11:33:40.426 iOSTest[34497:828682] 2222 0x600000260080>{number = 3, name = (null)}
2017-10-24 11:33:41.426 iOSTest[34497:828660] 11111 0x608000261d80>{number = 4, name = (null)}
2017-10-2411:33:41.427 iOSTest[34497:828660] 完成 0x608000261d80>{number = 4, name = (null)}
2017-10-2411:33:41.427 iOSTest[34497:828365] 通知主線程刷新UI 0x60800007b980>{number = 1, name = main}
這樣我們使用group可以實(shí)現(xiàn)幾個(gè)任務(wù)之間的依賴關(guān)系唐含。
然而有時(shí)我們的任務(wù)一層一層的嵌套了多個(gè)Block浅浮,這個(gè)時(shí)候,就應(yīng)該使用如下代碼方式:
//創(chuàng)建分組
dispatch_group_t group =dispatch_group_create();
//創(chuàng)建隊(duì)列
dispatch_queue_t queue =dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);
//往分組中添加任務(wù)
dispatch_group_async(group, queue, ^{
void (^task)(void) = ^{
[NSThreadsleepForTimeInterval:2];//模擬耗時(shí)操作
NSLog(@"11111 %@", [NSThreadcurrentThread]);
};
dispatch_async(dispatch_get_global_queue(0,0), task);
NSLog(@"11111---- %@", [NSThreadcurrentThread]);
});
//往分組中添加任務(wù)
dispatch_group_async(group, queue, ^{
void (^task)(void) = ^ {
[NSThreadsleepForTimeInterval:1];//模擬耗時(shí)操作
NSLog(@"2222 %@", [NSThreadcurrentThread]);
};
dispatch_async(dispatch_get_global_queue(0,0), task);
NSLog(@"2222------- %@", [NSThreadcurrentThread]);
});
//分組中任務(wù)完成以后通知該block執(zhí)行
dispatch_group_notify(group, queue, ^{
NSLog(@"完成 %@", [NSThreadcurrentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"通知主線程刷新UI %@", [NSThreadcurrentThread]);
});
});
執(zhí)行結(jié)果:
2017-10-24 11:44:06.447 iOSTest[34981:881063] 2222------- {number = 4, name = (null)}
2017-10-2411:44:06.447 iOSTest[34981:881046] 11111---- {number = 3, name = (null)}
2017-10-24 11:44:06.448iOSTest[34981:881046] 完成 0x600000071f40>{number = 3, name = (null)}
2017-10-24 11:44:06.450iOSTest[34981:880987] 通知主線程刷新UI 0x60000006c340>{number = 1, name = main}
2017-10-2411:44:07.450 iOSTest[34981:881064] 2222 0x6000000708c0>{number = 5, name = (null)}
2017-10-2411:44:08.452 iOSTest[34981:881049] 11111 0x61000006d5c0>{number = 6, name = (null)}
根據(jù)執(zhí)行結(jié)果可以看出捷枯,當(dāng)主線程執(zhí)行的時(shí)候滚秩,然而其他兩個(gè)任務(wù)中并沒有真正的完成,因?yàn)榱硗鈨蓚€(gè)任務(wù)中嵌套了子任務(wù)淮捆,那問題來了郁油,其他兩個(gè)任務(wù)還沒有完成就執(zhí)行主線程,但是我們需要的是其他兩個(gè)任務(wù)完成才需要執(zhí)行主線程攀痊,別急桐腌,group給我們提供了dispatch_group_enter()與dispatch_group_leave()方法來組合運(yùn)用,值得注意的是苟径,這兩個(gè)方法一定需要成對使用案站,要不然有時(shí)間又出現(xiàn)一些莫名其妙的bug問題。
代碼如下:
//創(chuàng)建分組
dispatch_group_t group =dispatch_group_create();
//創(chuàng)建隊(duì)列
dispatch_queue_t queue =dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);
//往分組中添加任務(wù)
dispatch_group_enter(group);
dispatch_async(queue, ^{
void (^task)(void) = ^{
[NSThreadsleepForTimeInterval:2];//模擬耗時(shí)操作
NSLog(@"11111 %@", [NSThreadcurrentThread]);
dispatch_group_leave(group);
};
dispatch_async(dispatch_get_global_queue(0,0), task);
NSLog(@"11111---- %@", [NSThreadcurrentThread]);
});
//往分組中添加任務(wù)
dispatch_group_enter(group);
dispatch_async(queue, ^{
void (^task)(void) = ^ {
[NSThreadsleepForTimeInterval:1];//模擬耗時(shí)操作
NSLog(@"2222 %@", [NSThreadcurrentThread]);
dispatch_group_leave(group);
};
dispatch_async(dispatch_get_global_queue(0,0), task);
NSLog(@"2222------- %@", [NSThreadcurrentThread]);
});
//分組中任務(wù)完成以后通知該block執(zhí)行
dispatch_group_notify(group, queue, ^{
NSLog(@"完成 %@", [NSThreadcurrentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"通知主線程刷新UI %@", [NSThreadcurrentThread]);
});
});
執(zhí)行結(jié)果如下:
2017-10-24 11:48:05.641 iOSTest[35128:902591] 11111---- {number = 3, name = (null)}
2017-10-2411:48:05.641 iOSTest[35128:902608] 2222------- {number = 4, name = (null)}
2017-10-24 11:48:06.644iOSTest[35128:902609] 2222 0x60000006cb00>{number = 5, name = (null)}
2017-10-24 11:48:07.644iOSTest[35128:902593] 11111 0x6080000721c0>{number = 6, name = (null)}
2017-10-24 11:48:07.644iOSTest[35128:902593] 完成 0x6080000721c0>{number = 6, name = (null)}
2017-10-24 11:48:07.645iOSTest[35128:902524] 通知主線程刷新UI 0x61000006e280>{number = 1, name = main}
這樣我們想要的得到的結(jié)果就實(shí)現(xiàn)了棘街。
A蟆盐,B,C三個(gè)任務(wù)并發(fā)執(zhí)行,但是C要等A遭殉,B執(zhí)行完成之后再執(zhí)行石挂。
信號量:
// 創(chuàng)建一個(gè)信號,value:信號量
dispatch_semaphore_create(<#long value#>)
// 使某個(gè)信號的信號量+1
dispatch_semaphore_signal(<#dispatch_semaphore_t dsema#>)
// 某個(gè)信號進(jìn)行等待或等待降低信號量 timeout:等待時(shí)間险污,永遠(yuǎn)等待為 DISPATCH_TIME_FOREVER
dispatch_semaphore_wait(<#dispatch_semaphore_t dsema#>, <#dispatch_time_t timeout#>)
正常的使用順序是先降低然后再提高痹愚,這兩個(gè)函數(shù)通常成對使用。
兩種方法
-(void)dispatch_group_function1
{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_queue_create("com.dispatch.test", DISPATCH_QUEUE_CONCURRENT), ^{
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.baidu.com"]];
NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// 請求完成罗心,可以通知界面刷新界面等操作
NSLog(@"第一步網(wǎng)絡(luò)請求完成");
// 使信號的信號量+1里伯,這里的信號量本來為0,+1信號量為1(綠燈)
dispatch_semaphore_signal(semaphore);
}];
[task resume];
// 以下還要進(jìn)行一些其他的耗時(shí)操作
NSLog(@"耗時(shí)操作繼續(xù)進(jìn)行");
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
});
dispatch_group_async(group, dispatch_queue_create("com.dispatch.test", DISPATCH_QUEUE_CONCURRENT), ^{
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.github.com"]];
NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// 請求完成渤闷,可以通知界面刷新界面等操作
NSLog(@"第二步網(wǎng)絡(luò)請求完成");
// 使信號的信號量+1,這里的信號量本來為0脖镀,+1信號量為1(綠燈)
dispatch_semaphore_signal(semaphore);
}];
[task resume];
// 以下還要進(jìn)行一些其他的耗時(shí)操作
NSLog(@"耗時(shí)操作繼續(xù)進(jìn)行");
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"刷新界面等在主線程的操作");
});
}
2019-02-24 18:19:16.251067+0800 Semaphore[33094:12267734] 耗時(shí)操作繼續(xù)進(jìn)行
2019-02-24 18:19:16.251071+0800 Semaphore[33094:12267735] 耗時(shí)操作繼續(xù)進(jìn)行
2019-02-24 18:19:16.549563+0800 Semaphore[33094:12267748] 第一步網(wǎng)絡(luò)請求完成
2019-02-24 18:19:18.091922+0800 Semaphore[33094:12267737] 第二步網(wǎng)絡(luò)請求完成
2019-02-24 18:19:18.092222+0800 Semaphore[33094:12267662] 刷新界面等在主線程的操作
設(shè)定的信號值為2飒箭,先執(zhí)行兩個(gè)線程,等執(zhí)行完一個(gè)蜒灰,才會繼續(xù)執(zhí)行下一個(gè)弦蹂,保證同一時(shí)間執(zhí)行的線程數(shù)不超過2。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//任務(wù)1
dispatch_async(queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"run task 1");
sleep(1);
NSLog(@"complete task 1");
dispatch_semaphore_signal(semaphore);
});
//任務(wù)2
dispatch_async(queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"run task 2");
sleep(1);
NSLog(@"complete task 2");
dispatch_semaphore_signal(semaphore);
});
//任務(wù)3
dispatch_async(queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"run task 3");
sleep(1);
NSLog(@"complete task 3");
dispatch_semaphore_signal(semaphore);
});
2019-02-24 18:31:02.447769+0800 Semaphore[33286:12284312] run task 1
2019-02-24 18:31:02.447767+0800 Semaphore[33286:12284310] run task 2
2019-02-24 18:31:03.450756+0800 Semaphore[33286:12284312] complete task 1
2019-02-24 18:31:03.450756+0800 Semaphore[33286:12284310] complete task 2
2019-02-24 18:31:03.450997+0800 Semaphore[33286:12284311] run task 3
2019-02-24 18:31:04.454259+0800 Semaphore[33286:12284311] complete task 3