GCD常用用法

作者: senpaiLi | 来源:发表于2018-09-17 14:47 被阅读15次

    GCD我们用的已经很多了,同步异步,并行串行各位博主也有了很详细的介绍,我在这里总结一下平时会常用的几种方法。

    GCD的几个重要概念:任务、队列、队列组、并行、串行、同步、异步

    1.异步并行,可以开启多个线程,任务交替(同时)执行。

    一般用来处理耗时的操作,如网络请求、IO操作、写入读取等。

    /**
    创建一个并行队列
    
    @param "net.bujige.testQueue" 该队列的唯一标识字符串
    @param DISPATCH_QUEUE_CONCURRENT 代表并行队列
    */
    dispatch_queue_t queue = dispatch_queue_create("net.ly.testQueue", DISPATCH_QUEUE_CONCURRENT);
    
    或者使用dispatch_get_global_queue来获取并行队列
    /**
    获取一个并行队列
    
    @param DISPATCH_QUEUE_PRIORITY_DEFAULT 队列优先级
    */
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
    
    
    /**
    加入两个异步任务
    */
    dispatch_async(queue, ^{
        NSLog(@"任务1");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任务2");
    });
    
    此时任务一任务二同时执行,不会互相影响。
    
    2.异步串行,可以开启一个线程,任务一个接一个执行。

    我们经常会遇到这种需求,比如一张图片加载完成之后,再去执行下一张图片,这时候就可以用到异步串行。
    注意:UI操作都要放到主线程。

    /**
    创建一个串行队列
    
    @param "net.ly.testQueue" 该队列的唯一标识字符串
    @param DISPATCH_QUEUE_SERIAL 代表串行队列
    */
    dispatch_queue_t queue = dispatch_queue_create("net.ly.testQueue", DISPATCH_QUEUE_SERIAL);
    
    /**
    加入两个异步任务
    */
    dispatch_async(queue, ^{
        NSLog(@"任务1");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任务2");
    });
    
    任务1执行结束之后,任务2开始执行。且均没有在主线程操作。
    
    3.回到主线程(线程间的通信)。

    之前我们了解过,UI操作都要放到主线程。必须要用异步任务,否则会阻塞主线程并有可能造成闪退(xcode9以下)

    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"回到主线程");
    });
    
    4.栅栏方法:dispatch_barrier_async

    我们有时需要异步执行两组操作,而且第一组操作执行完之后,才能开始执行第二组操作。这样我们就需要一个相当于栅栏一样的一个方法将两组异步执行的操作组给分割起来,当然这里的操作组里可以包含一个或多个任务。这就需要用到dispatch_barrier_async方法在两个操作组间形成栅栏。

    dispatch_barrier_async函数会等待前边追加到并发队列中的任务全部执行完毕之后,再将指定的任务追加到该异步队列中。然后在dispatch_barrier_async函数追加的任务执行完毕之后,异步队列才恢复为一般动作,接着追加任务到该异步队列并开始执行。
    引用

    栅栏方法一般用在异步并行才有意义。用得好的话很强大的功能。

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSLog(@"任务1");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任务2");
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"栅栏");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任务3");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任务4");
    });
    
    任务1、2同时执行,且均结束之后,执行栅栏方法,然后才会去执行任务3、任务4
    
    5.延时方法:dispatch_after

    最常用到的GCD方法

    需要注意的是:dispatch_after函数并不是在指定时间之后才开始执行处理,而是在指定时间之后将任务追加到主队列中。严格来说,这个时间并不是绝对准确的,但想要大致延迟执行任务,dispatch_after函数是很有效的。

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"2s后执行");
    });
    
    6.once方法:dispatch_once

    一般用在单例、读取APP信息时用到,避免重复执行复杂的操作

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"执行一次");
    });
    
    7.GCD快速遍历:dispatch_apply

    dispatch_apply函数会等待全部任务执行完毕。

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(6, queue, ^(size_t) {
        //循环操作
    });
    

    一般使用并行队列。如果是在串行队列中使用 dispatch_apply,那么就和 for 循环一样,按顺序同步执行。可这样就体现不出快速迭代的意义了。

    8.GCD定时器:

    一般开发不会直接使用NSTimer的定时器,加入线程,释放等步骤都会出现一系列细节问题需要注意。而一个封装好的GCD定时器,会完成我们的大部分需求。

    注意:dispatch_source_t对象必须要设置成属性,不然会被提前释放掉导致循环提前结束

    /**
    获取一个并行线程
    
    @param DISPATCH_QUEUE_PRIORITY_DEFAULT 线程优先级
    */
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //创建定时器
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
    /**
    设置时间属性
    
    @param source  dispatch_source_t对象
    @param start      开始时间
    @param interval  时间间隔
    */
    dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), 2 * NSEC_PER_SEC, 0);
    
    //handler,eventBlock即为定时器的回调block
    dispatch_source_set_event_handler(_timer, eventBlock);
    
    
    //取消(_timer会被释放掉)
    dispatch_source_cancel(_timer);
    //暂停
    dispatch_suspend(_timer);
    //继续
    dispatch_resume(_timer);
    

    定时器开始时必须调用dispatch_resume方法。
    dispatch_suspend之后,重新resume,会补上这段时间缺失的方法。举个简单的例子,2s间隔的定时器,suspend10s后resume,会一次性执行5次eventBlock方法。这里要注意下。

    常用的几个GCD方法就介绍到这里了,下面我来着重描述下队列组的用法,放到下一篇博客里面。☺

    相关文章

      网友评论

        本文标题:GCD常用用法

        本文链接:https://www.haomeiwen.com/subject/tzyknftx.html