《Objective-C 高级编程》学习笔记3-GCD

739 阅读3分钟


狮子头镇楼

《Objective-C 高级编程》学习笔记1-内存管理

《Objective-C 高级编程》学习笔记2-Blocks


1   什么是 GCD

将应用程序中记述的线程管理用的代码在系统级中实现。开发者只需要定义想要执行的任务并追加到适当的 Dispatch Queue 中,GCD就能生成必要的线程并计划执行任务。


2   GCD 的 API

dispatch_async(queue, ^{
    /*
     * 想执行的任务
     */
})

该源码使用 Block 语法“定义想执行的任务”,通过 dispatch_async 函数“追加”赋值在变量 queue 的“Dispatch Queue中”。

2.1、Dispatch Queue

Dispatch Queue:执行处理的等待队列。有两种:

  • Serial Dispatch Queue,串行队列
  • Concurrent Dispatch Queue,并行队列

2.2、dispatch_queue_create

//创建串行队列
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.gcd.mySerialDispatchQueue", NULL);
dispatch_async(mySerialDispatchQueue, ^{
    //在串行队列中执行Block
});
    
//创建并行队列
dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.gcd.myConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myConcurrentDispatchQueue, ^{
    //在并行队列中执行Block
});

2.3、Main Dispatch Queue / Global Dispatch Queue

这是系统标准提供的 Dispatch Queue

2.3.1、Main Dispatch Queue

主线程执行的的 Dispatch Queue,因为主线程只有一个,所以它一定是串行队列

追加到 Main Dispatch Queue 的处理在主线程的 RunLoop 中执行。因此用户界面的操作等一些必须在主线程中执行的处理追加到 Main Dispatch Queue 中使用。

2.3.2、Global Dispatch Queue

是所有应用程序都能够使用的并行队列,它有四个优先级。


///主队列获取
dispatch_queue_t mdq = dispatch_get_main_queue();
    
//全局队列,执行优先级:高
dispatch_queue_t gdq_high = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
//全局队列,执行优先级:中
dispatch_queue_t gdq_default = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//全局队列,执行优先级:低
dispatch_queue_t gdq_low = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
//全局队列,执行优先级:后台
dispatch_queue_t gdq_background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

2.4、dispatch_set_target_queue

dispatch_queue_create 函数生成的 Dispatch Queue 不管是 串行队列 还是 并行队列,都使用与默认优先级 Global Dispatch Queue 相同执行优先级的线程。可使用 dispatch_set_target_queue 函数变更 Dispatch Queue 的执行优先级。

2.5、dispatch_after

可使用 dispatch_after 执行指定时间后执行的处理。注意:dispatch_after 函数并不是在指定时间后执行处理,而只是在指定时间追加处理到 Dispatch Queue 。

dispatch_time_t dt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
dispatch_after(dt, dispatch_get_main_queue(), ^{
    //执行操作的block
});

2.6、Dispatch Group

在追加到 Dispatch Queue 中的多个处理全部结束后想执行结束处理的时候使用。

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(@"blk0"); });
dispatch_group_async(group, queue, ^{ NSLog(@"blk1"); });
dispatch_group_async(group, queue, ^{ NSLog(@"blk2"); });
dispatch_group_async(group, queue, ^{ NSLog(@"blk3"); });
    
dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"done"); });

2.7、dispatch_sync

  • async 意味着 “非同步”,dispatch_async 函数不做任何等待。
  • sync 意味着 “同步”,dispatch_sync 函数会将指定的 Block “同步” 追加到指定的 Dispatch Queue 中。在追加 Block 结束之前,dispatch_sync 函数会一直等待。

dispatch_sync 使用不当会造成一个很严重的问题:死锁。

dispatch_sync(dispatch_get_main_queue(), ^{
    NSLog(@"同步任务在 %@ 执行", [NSThread currentThread]);
});

//1、主线程正在执行主队列的任务;
//2、一个同步任务过来了,于是,主线程立即等待;
//3、同步任务在等主线程当前任务完成,然而主线程在等待这个同步任务执行;
//4、于是就造成了相互等待的情况。

2.8、dispatch_once

dispatch_once 函数是保证在应用程序执行中只执行以此指定处理的API。如初始化单例。

+ (instancetype)share {
    static id instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}


3   GCD 实现

3.1、Dispatch Queue

GCD 的 Dispatch Queue 非常方便,实现 GCD 需要:

  • 用于管理追加的 Block 的 C语言层实现的 FIFO 队列。
  • Atomic 函数中实现的用于排他控制的轻量级信号。
  • 用于管理线程的C语言层实现的一些容器。