前言
近期工作比较空闲,项目上线重构任务还没有开始,所以这几天学习了一些GCD的知识,发现了一个挺有意思也挺有用的东西,和大家分享下,我绝对不是第一个写这些东西的人,全当我自己的学习总结就好,欢迎批评指正
我们来模拟一个场景,我要从服务器下载4张图片,之后将四张图片拼接成一张,显而易见,图片这种耗时操作我们肯定要在子线程去完成该任务,由于图片的大小可能还不一样,我们分别开4个异步的任务去分别下载4张图片,但是问题来了,我拼接4张图片的时候必这四张图片必须全部都下载完成了才能进行,面对这样的场景,我来给大家介绍两个可以实现上述逻辑的方法,使用dispatch_barrier_async
或dispatch_group_async
dispatch_barrier_async
首先我们来看看下面这段代码
dispatch_queue_t queue = dispatch_queue_create("ioScoderZZJ", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"----耗时任务1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----耗时任务2-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----耗时任务3-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----耗时任务4-----%@", [NSThread currentThread]);
});
看看打印,众所周知,先执行哪个操作你是不能控制的
来我们接着讲dispatch_barrier_async
,如果我们写了dispatch_barrier_async
函数后,我们改造下代码,如下(不高亮了,我也不知道咋回事..)
dispatch_queue_t queue = dispatch_queue_create("ioScoderZZJ", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"----耗时任务1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----耗时任务2-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----耗时任务3-----%@", [NSThread currentThread]);
});
//这里我们加上了上面的那个函数
dispatch_barrier_async(queue, ^{
NSLog(@"----barrier-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----耗时任务4-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----耗时任务4-----%@", [NSThread currentThread]);
});
再看看打印情况
我们发现任务1\2\3和4\5被该方法隔开,所以当前三个全部执行完成后才会接着执行后面的两个异步任,一个dispatch barrier 允许在一个并发队列中创建一个同步点。当在并发队列中遇到一个barrier, 他会延迟执行barrier的block,等待所有在barrier之前提交的blocks执行结束。 这时,barrier block自己开始执行.之后, 队列继续正常的执行操作
这样的实现思路我们就可以实现上面说的4张图片下载合成的问题,完全可以在barrier的block中完成图片合成的相关操作,并且不必担心4个图片为空的问题
*注意:我们一定要使用自己创建的队列
dispatch_queue_t queue = dispatch_queue_create("ioScoderZZJ", DISPATCH_QUEUE_CONCURRENT);
,如果使用全局并发队列会产生错误的结果
dispatch_group_async
如果只是使用一个串行队列时,只要将想执行的处理全部追加到该串行队列中并在最后追加结束处理即可,但是在使用并发队列时,可能会同时使用多个Dispatch Queue时,源代码就会变得很复杂,这里我们介绍一个dispatch_group_async
概念
我们接着改进上面的代码,如下
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"----耗时任务1-----%@", [NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"----耗时任务2-----%@", [NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"----耗时任务3-----%@", [NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"----耗时任务4-----%@", [NSThread currentThread]);
});
//线程组全执行完毕才会调用
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"----结束-----");
});
打印结果
同样的上面的任务执行完毕后会调用
dispatch_group_notify
这个函数,按照这个思路我们依然实现上面图片的下载和拼接操作
最后
这块东西比较简单也好理解,代码量也很少,如果日常开发中碰到了在一些异步操作中需要全部完成后再去执行别的操作的时候,不妨使用这种方法来寻求"同步点",希望我的文章可以帮助到你
我是一只iOS开发的小菜鸡,希望有一天成为雄鹰
旅途很长 还需修行