您的位置:首页 > 其它

GCD 之四:Dispatch Group

2014-04-07 18:39 134 查看
在追加到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 queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{NSLog(@"block0");});
dispatch_group_async(group, queue, ^{NSLog(@"block1");});
dispatch_group_async(group, queue, ^{NSLog(@"block2");});

dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(@"done");});
dispatch_release(group);

源代码的执行结果如下:

block0
block2
block1
done

因为向Global Dispatch Queue即Concurrent Dispatch Queue追加处理,多个线程并行执行,所以追加处理的执行顺序不定。执行时会发生变化,但是此执行结果的done一定是最后输出的。

无论向什么样的Dispatch Queue中追加处理,使用Dispatch Group都可监视这些处理执行的结束。一旦检测到所有处理执行结束,就可将结束的处理追加到Dispatch Queue中。这就是使用Dispatch Queue的原因。

首先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_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中,将第一个参数指定为要监视的Dispatch Group。在追加到该Dispatch Group的全部处理执行结束时,将第三个参数的Block追加到第二个参数的Dispatch Queue中。在dispatch_group_notify函数中不管指定什么样的Dispatch Queue,属于Dispatch Group的全部处理在追加指定的Block时都已执行结束。

另外,在Dispatch Group中也可以使用dispatch_group_wait函数公等待全部处理执行结束。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{NSLog(@"block0");});
dispatch_group_async(group, queue, ^{NSLog(@"block1");});
dispatch_group_async(group, queue, ^{NSLog(@"block2");});

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);

dispatch_group_wait函数的第二个参数指定为等待的时间(超时)。它属于dispatch_time_t类型的值。该源代码使用DISPATCH_TIME_FOREVER,意味着永久等待。只要属于Dispatch Group的处理尚未执行结束,就会一直等待,中途不能取消。

指定等待间隔为1秒时可做如下处理:

dispatch_time_time time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
long  result = dispatch_group_wait(group, time);
if (result == 0) {
/*
* 属于Dispatch Group的全部处理执行结束
*/
} else {
/*
* 属于Dispatch Group的某一个处理还在执行中
*/
}

如果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(group, DISPATCH_TIME_NOW);

在主线程的RunLoop的每次循环中,中检查执行是否结束,从而不耗费多余的等待时间,虽然这样也可以,但一般在这种情况下,还是推荐用dispatch_group_notify函数追加到结束处理到Main Dispatch Queue中,因为dispatch_group_notify函数可以简化源代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: