3.2.6 Dispatch Group
在追加到Dispatch Queue中的多个处理全部结束后想执行结束处理,这种情况会经常出现。
在只使用一个Serial Dispatch Queue时,只要将想要执行的处理全部追加到该Serial Dispatch Queue 中并在最后追加结束处理,即可实现。
但是在使用Concurrent Dispatch Queue时或同时使用多个Dispatch Queue时,源代码就会变得颇为复杂。
- 在这种情况下使用Dispatch Group. 例如下面源代码为:追加3个Block到Global Dispatch Queue, 这些Block如果全部执行完毕,就会执行Main Dispatch Queue 中结束处理用的Block.
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t grouop = dispatch_group_create();
dispatch_group_async(grouop, queue1, ^{
NSLog(@"blk0");
NSLog(@"%@",[NSThread currentThread]);
});
dispatch_group_async(grouop, queue1, ^{
NSLog(@"blk1");
NSLog(@"%@",[NSThread currentThread]);
});
dispatch_group_async(grouop, queue1, ^{
NSLog(@"blk2");
NSLog(@"%@",[NSThread currentThread]);
});
dispatch_group_notify(grouop, dispatch_get_main_queue(), ^{
NSLog(@"fininsh");
NSLog(@"%@",[NSThread currentThread]);
});
因为向Global Dispatch Queue 即 Concurrent Dispatch Queen追加处理,多个线程并行执行,所以追加处理的执行顺序不定。执行时会发生变化,但是此执行结果的finish一定是最后输出的。
无论向什么样的Dispatch Queue中追加处理,使用Dispatch Group都可监视这些处理执行的结束。一旦检测到所有的处理执行结束,就可将结束的处理追加到Dispatch Queue中。这就是使用Dispatch Group的原因。
首先dispatch_group_create 函数生成dispatch_group_t类型的Dispatch Group.如dispatch_group_create 函数名中所含的create所示,该Dispatch Group与Dispatch Queue相同,在使用结束后需要通过dispatch release函数释放。
dispatch_group_async函数与dispatch_async函数相同,都追加Block到指定的Dispatch Queue中。与dispatch_async函数不同的是指定生成的Dispatch Group为第一个参数。指定的Block属于指定的Dispatch Group.
另外,与追加Block到Dispatch Queue时同样,Block通过dispatch_retain函数持有Dispatch Group,从而使得该Block属于Dispatch Group.这样如果Block执行完毕,该Block就通过dispatch_release函数释放持有的Dispatch Group.一旦Dispatch_Group使用结束,不用考虑属于该Dispatch Group的Block,立即通过Dispatch_release 函数释放即可。
在追加Dispatch Group 中的处理全部执行结束时,该源代码中使用dispatch_group_notify函数会将执行的Block追加到Dispatch Queue中,将第三个参数的block追加到第二个参数的Dispatch Queue中。在dispatch_group_notify函数中不管指定什么样的Dispatch Queue,属于Dispatch Group 的全部处理在追加指定的Block时都已执行结束。
另外,在Dispatch Group中也可以使用dispatch_group_wait函数仅等待全部处理执行结束。
-(void)dispatch_wait {
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t grouop = dispatch_group_create();
dispatch_group_async(grouop, queue1, ^{
NSLog(@"blk0");
NSLog(@"%@",[NSThread currentThread]);
});
dispatch_group_async(grouop, queue1, ^{
NSLog(@"blk1");
NSLog(@"%@",[NSThread currentThread]);
});
dispatch_group_async(grouop, queue1, ^{
NSLog(@"blk2");
NSLog(@"%@",[NSThread currentThread]);
});
dispatch_group_wait(grouop, DISPATCH_TIME_FOREVER);
// dispatch_release(grouop);
}
dispatch_group_wait函数的第二个参数指定为等待的时间(超时时间)。它属于dispatch_time_t 类型的值。该源码使用DISPATCH_TIME_FOREVER,意味着永久等待,只要Dispatch Group的处理尚未执行结束,就会一直等待,中途不能取消。
如同dispatch_after函数说明中的那样,指定等待时间间隔为1秒时应做如下处理。
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull *NSEC_PER_SEC);
long result = dispatch_group_wait(grouop, time);
if (result == 0) {
/**
属于Dispatch Group的全部处理执行结束
*/
NSLog(@"执行完毕");
}else {
/**
属于Dispatch Group的某一个处理还在执行
*/
NSLog(@"还在执行");
}
如果dispatch_group_wait函数的返回值不为0,就意味着虽然经过了指定的时间,但属于Dispatch Group的某一个处理还在执行中。如果返回为0,那么全部处理执行结束。当等待时间为DISPATCH_TIME_FOREVER、由dispatch_group_wait函数返回时,由于属于Dispatch Group的处理必定全部执行结束,因此返回值恒为0,
这里的“等待”是什么意思呢?这意味着一旦调用dispatch_group_wait函数,该函数就处于调用的状态而不返回。即执行dispatch_group_wait函数的现在的线程(当前线程)停止。在经过dispatch_group_wait函数中指定的时间或属于指定Dispatch Group的处理全部执行结束之前,执行该函数的线程停止。
指定DISPATCH_TIME_NOW,则不用任何等待即可判定属于Dispatch Group的处理是否执行结束。
long result = dispatch_group_wait(grouop, DISPATCH_TIME_NOW);
在主线程的RunLoop的每次循环中,可检查执行可否结束,从而不耗费多余的等待时间,虽然这样也可以,但一般在这种情形下,还是推荐用dispatch_group_notify函数追加结束处理到Main Dispatch Queue中,这是因为dispatch_group_notify函数可以简化源代码。