在开发中,我们经常会碰到一类问题,A任务开始执行的前提是B任务执行完成了,针对这种,如果只是简简单单的一个任务接一个任务,可能使用block 嵌套也可以做到,但是如果是C任务开始执行需要等A、B两个异步任务完成,这个呢?这里就需要使用到一些GCD的高级用法。
1、gcd的分组
//创建分组
dispatch_group_t group = dispatch_group_create();
//创建队列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
//往分组中添加任务
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:2];//模拟耗时操作
NSLog(@"11111 %@", [NSThread currentThread]);
});
//往分组中添加任务
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:1];//模拟耗时操作
NSLog(@"2222 %@", [NSThread currentThread]);
});
//分组中任务完成以后 通知该block 执行
dispatch_group_notify(group, queue, ^{
NSLog(@"完成 %@", [NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"通知主线程刷新UI %@", [NSThread currentThread]);
});
});
执行结果
2017-09-15 11:33:40.426 iOSTest[34497:828682] 2222 0x600000260080>{number = 3, name = (null)}
2017-09-15 11:33:41.426 iOSTest[34497:828660] 11111 0x608000261d80>{number = 4, name = (null)}
2017-09-15 11:33:41.427 iOSTest[34497:828660] 完成 0x608000261d80>{number = 4, name = (null)}
2017-09-15 11:33:41.427 iOSTest[34497:828365] 通知主线程刷新UI 0x60800007b980>{number = 1, name = main}
根据执行结果,可知,使用group可以实现多任务之间的依赖关系,这是直接往group中添加任务,但是有时候,我们的任务一层一层的嵌套了多层Block,这个时候,代码如下:
//创建分组
dispatch_group_t group = dispatch_group_create();
//创建队列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
//往分组中添加任务
dispatch_group_async(group, queue, ^{
void (^task)(void) = ^{
[NSThread sleepForTimeInterval:2];//模拟耗时操作
NSLog(@"11111 %@", [NSThread currentThread]);
};
dispatch_async(dispatch_get_global_queue(0, 0), task);
NSLog(@"11111---- %@", [NSThread currentThread]);
});
//往分组中添加任务
dispatch_group_async(group, queue, ^{
void (^task)(void) = ^ {
[NSThread sleepForTimeInterval:1];//模拟耗时操作
NSLog(@"2222 %@", [NSThread currentThread]);
};
dispatch_async(dispatch_get_global_queue(0, 0), task);
NSLog(@"2222------- %@", [NSThread currentThread]);
});
//分组中任务完成以后 通知该block 执行
dispatch_group_notify(group, queue, ^{
NSLog(@"完成 %@", [NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"通知主线程刷新UI %@", [NSThread currentThread]);
});
});
执行结果:
2017-09-15 11:44:06.447 iOSTest[34981:881063] 2222------- {number = 4, name = (null)}
2017-09-15 11:44:06.447 iOSTest[34981:881046] 11111---- {number = 3, name = (null)}
2017-09-15 11:44:06.448 iOSTest[34981:881046] 完成 0x600000071f40>{number = 3, name = (null)}
2017-09-15 11:44:06.450 iOSTest[34981:880987] 通知主线程刷新UI 0x60000006c340>{number = 1, name = main}
2017-09-15 11:44:07.450 iOSTest[34981:881064] 2222 0x6000000708c0>{number = 5, name = (null)}
2017-09-15 11:44:08.452 iOSTest[34981:881049] 11111 0x61000006d5c0>{number = 6, name = (null)}
根据结果我们可以知道,其实刷新主线程的时候,其他两个任务中并没有真正的完成,因为另外两个任务中嵌套了子任务,你就会发现这样执行任务还是不能满足需求,那要怎么做呢?其实group提供了dispatch_group_enter()与dispatch_group_leave()方法来自己组合,但是一定要注意,这两个方法一定需要成对使用,否则会引起莫名Bug。代码如下:
//创建分组
dispatch_group_t group = dispatch_group_create();
//创建队列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
//往分组中添加任务
dispatch_group_enter(group);
dispatch_async(queue, ^{
void (^task)(void) = ^{
[NSThread sleepForTimeInterval:2];//模拟耗时操作
NSLog(@"11111 %@", [NSThread currentThread]);
dispatch_group_leave(group);
};
dispatch_async(dispatch_get_global_queue(0, 0), task);
NSLog(@"11111---- %@", [NSThread currentThread]);
});
//往分组中添加任务
dispatch_group_enter(group);
dispatch_async(queue, ^{
void (^task)(void) = ^ {
[NSThread sleepForTimeInterval:1];//模拟耗时操作
NSLog(@"2222 %@", [NSThread currentThread]);
dispatch_group_leave(group);
};
dispatch_async(dispatch_get_global_queue(0, 0), task);
NSLog(@"2222------- %@", [NSThread currentThread]);
});
//分组中任务完成以后 通知该block 执行
dispatch_group_notify(group, queue, ^{
NSLog(@"完成 %@", [NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"通知主线程刷新UI %@", [NSThread currentThread]);
});
});
执行结果如下:
2017-09-15 11:48:05.641 iOSTest[35128:902591] 11111---- {number = 3, name = (null)}
2017-09-15 11:48:05.641 iOSTest[35128:902608] 2222------- {number = 4, name = (null)}
2017-09-15 11:48:06.644 iOSTest[35128:902609] 2222 0x60000006cb00>{number = 5, name = (null)}
2017-09-15 11:48:07.644 iOSTest[35128:902593] 11111 0x6080000721c0>{number = 6, name = (null)}
2017-09-15 11:48:07.644 iOSTest[35128:902593] 完成 0x6080000721c0>{number = 6, name = (null)}
2017-09-15 11:48:07.645 iOSTest[35128:902524] 通知主线程刷新UI 0x61000006e280>{number = 1, name = main}
可以看出,我们想要的结果又回来了。但是这里有个比较重要的地方要注意,这个enter不要放到任务里面了,因为任务是异步执行的,可能会执行执行了下面的完成以后,才执行上面的任务了。