GCD 详解

常用的

  1. dispatch_get_main_queue 主队列
  2. dispatch_get_global_queue 全部并发的队列

通常的基本用法:

dispatch_async(dispatch_get_global_queue(0, 0), ^{

        // 执行 耗时的任务
        dispatch_async(dispatch_get_main_queue(), ^{

             // 执行完成后,回到主线程 刷新UI
            
        });
        
    });

主队列就不介绍了,直接说全局队列
dispatch_get_global_queue 有两个参数,第二个没什么用,苹果留给以后的扩展,第一个参数就是优先级了,在NSThread里面有设置优先级的属性Priority,在GCD里当然也是有的。

首先:

GCD 详解_第1张图片
三个不设置优先级的全局队列.png

可以看得出 dispatch_get_global_queue 是同时运行的,顺序也是不确定的。说明它是一个全局并发的队列
再看它的线程id,是三个不同的id,所以说明是创建了三个线程,然后异步执行。

优先级:
全局队列第一个参数:


GCD 详解_第2张图片
优先级.png

设置优先级后的效果

GCD 详解_第3张图片
设置优先级.png

我们给2设置了最高级别,但是却是3先开始的,但是结束的时候是2先结束的,所以说这个优先级设置也是有一定概率的,一般情况下优先级高的会比优先级低的先执行完。
但是 如果线程执行的任务复杂度不同,那么就会出现混乱的问题,因为还是为了保持一个顺序的话,那么我们就需要用到串行的队列了。GCD也给们我提供了串行的队列

串行队列,执行是有顺序的。

GCD 详解_第4张图片
串行队列.png

可以看的出来我们自己创建的队列queue 默认是串行的。两个参数,第一个是唯一标识,第二个就是设置 串行、并行。NULL默认为串行的。
看打印出来的结果 和 时间,可以看出来是串行的队列,一个执行完成再执行另一个的。
还有个重点:这是在一个线程里面执行的。不知道大家有没有看出来,你们看下面的线程id号是一样的。

参数 第二个参数 两种:

  1. DISPATCH_QUEUE_CONCURRENT 并行
  2. DISPATCH_QUEUE_SERIAL 串行
GCD 详解_第5张图片
并行队列.png

修改参数后就是并行的队列,三个线程并发执行。

学了这些,有没有一些问题呢? 首先呢,对于串行队列,我们可以在所有任务都完成的时候回到主线程然后去做一些其他的工作,你们有没有想一个问题:

实际开发中:有这种串行的队列开发的应用吗?没有吧,这样会阻塞当前线程,造成用户体验不好。实际开发中都是并行队列,异步执行。
那么问题来了:

多个接口并发执行,我想在所有接口都回调完成后刷新UI,怎么做?

两种解决方法:

  1. 加入标记位
  2. GCD的 dispatch_group_t

我们这里讲第二种。
GCD的dispatch_group_t就是为了解决多个接口并发执行,在最后执行完成 给予 回调 的问题的。
为什么呢?因为 它有个 dispatch_group_notify 这个方法,它会在队列中所有异步线程请求完后 回调!!!就是这么流弊。

GCD 详解_第6张图片
dispatch_group_t.png

代码就是这样的,看输出台,是不是在所有并发队列请求完成后回调的?si bu si ?
但是有个问题,不知道大家注意了没有,我们的notify回调不是在主线程中执行的,它是在系统分配在最后一个完成的队列中回调提示的。
所以解决办法就是把notify 方法的第二个参数换成主线程。

GCD 详解_第7张图片
主线程刷新UI.png

上面的不贴了,看效果是不是。


小tips:
因为GCD是自动控制线程的生命周期的,我们不需要关心线程的一些属性,所以一般主线程的name是main,所以的子线程的name都是null。


那么我们模拟两个数据请求接口


GCD 详解_第8张图片
模拟两个数据请求.png

这时候我们就可以把这两个请求数据的方法 放入到我们的 异步请求里面了。

GCD 详解_第9张图片
加入数据接口请求方法.png

看输出结果,好像跟我们预期的不太一样啊。在1、2任务刚开始的时候就提示全部完成了,然后刷新UI,刷新完后才真正的完成数据回调处理数据啊。感觉不对啊~~~!!怎么办?

其实仔细看你会发现,我们的这两个请求的Block都是异步请求对吧!然后把这两个异步请求放入到异步请求里面。这样就形成了异步套异步啊。!!!!!懂??外层异步不会持有request,所以外层的两个异步会瞬间完成,然后我们的dispatch_group_notify 会直接回调完成。但是在内层的请求却还在进行着。。。。那么我们改成同步group?呵呵告诉你没有dispatch_group_sync这方法,你自己创造去吧!呵呵哒!

那么怎么解决这样的问题呢?

  1. dispatch_group_enter();
  2. dispatch_group_leave();
GCD 详解_第10张图片
完美.png

这两个方法。1是在整个异步请求的过程中group持有 2是在异步请求完成后不在持有。所以这两行代码的意思就是把这个异步请求放入到group当中。 这样就和我们预期的效果是一样的了。

总结:

  1. dispatch_get_main_queue 主队列
  2. dispatch_get_global_queue 全局队列 有两个参数,第一个设置优先级,第二个目前没用。
  3. dispatch_async 异步执行
    dispatch_sync 同步执行
  4. dispatch_queue_create 创建一个队列 第一个参数是唯一标识,第二个是优先级。对象是dispatch_queue_t类型。
  5. dispatch_group_async 异步执行组队列
    dispatch_group_enter 从某时开始持有
    dispatch_group_leave 到某时不在持有
  6. dispatch_group_create 创建一个组 没有参数,对象是dispatch_group_t类型
  7. dispatch_group_notify 组内所以队列完成后 回调。注意,回调的不是在主线程中,需要UI刷新的 比如切到主线程中。

从以上的学习、分析,我们好像根本没有像NSThread的那种去创建见一个线程,去设置线程的属性,管理线程的生命周期。对吧!所以说GCD 是不需要去管理线程的。我只要是创建队列和组,告诉去干什么就可以了。是不是很容易,虽然代码可读性差。

你可能感兴趣的:(GCD 详解)