GCD是一套高度抽象化的多线程编程技术,使用它可以编写出高效的多线程代码。相比于 NSThread 和 Cocoa NSOperation,Apple更推荐我们使用GCD。GCD的适用范围通常是那种需要长时间CPU运算的场合,例如耗时较长的图形处理和算法执行。GCD有两宝:一个Dispatch
Queue(FIFO队列)和一个线程池,前者用来添加任务,后者用来执行任务。
Dispatch Queue也是一个对象(可以调用dispatch_retain和dispatch_release来进行保留和释放),它会按照先进先执行的顺序执行任务。任务一般都是block。在使用GCD的时候,我们常常会先创建一个Dispatch Queue,然后向它提交block。看起来很像我们创建一个数组对象然后往里添加元素。Dispatch Queue可以是并发的,也可以是串行的。
-并发的DQ:在底层,线程池会提供多个线程来执行任务,所以可以按序启动多个任务并发执行;
-串行的DQ:线程池只提供一个线程用来执行任务,所以后一个任务必须等到前一个任务执行结束才能开始;
我们使用的Dispatch Queue有以下几种:
Global Queue-全局并发队列,由整个进程共享。队列中的任务按照FIFO顺序执行,同一时间可同时执行多个任务。
// 第1个参数表示队列执行的优先级: // DISPATCH_QUEUE_PRIORITY_HIGH-高优先级 // DISPATCH_QUEUE_PRIORITY_DEFAULT-中优先级 // DISPATCH_QUEUE_PRIORITY_LOW-低优先级 // DISPATCH_QUEUE_PRIORITY_BACKGROUND-最低优先级 // 第2个参数暂不支持,传0即可; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
Main Queue-主线程队列,属于串行队列。队列中的任务按照FIFO顺序在主线程中执行,因为是串行队列,同一时间只能执行一个任务。
dispatch_queue_t queue = dispatch_get_main_queue();
用户队列-用户自定义创建,可并发可串行。同样的队列中的任务按照FIFO顺序执行。
// 第一个参数: // 队列ID,需要传递一个字符串,命名分格采用类似com.example.myqueue的格式; // 第二个参数: // 在ios 4.3以前不支持,传NULL即可; // 在ios 4.3以后,这个参数表示队列类型。DISPATCH_QUEUE_SERIAL-创建一个串行队列;DISPATCH_QUEUE_CONCURRENT-创建一个并发队列; dispatch_queue_t queue = dispatch_queue_create("", NULL);
常用的GCD接口有哪些?
1、dispatch_async
作用:提交block至指定的队列中并异步执行,函数在第一时间返回。常见用法如下
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 耗时的操作 dispatch_async(dispatch_get_main_queue(), ^{ // 更新界面 }); });
2、dispatch_group_async(1) / dispatch_group_wait (2)/ dispatch_group_notify(3)
作用:(1)提交block至指定队列中并和一个dispatch_group_t对象关联,函数异步执行将在第一时间返回;
(2)同步等待至指定group中的block执行完毕或执行超时函数才返回;
(3)设置观察某个指定的group,等group中的block全部执行完毕后,向指定的queue提交block并异步执行;
这3个方法常常是搭配使用的,例如dispatch_group_async/dispatch_group_wait搭配
// 创建队列和组 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); // 向队列中添加block并关联组 dispatch_group_async(group, queue, ^{ // 耗时操作1 }); dispatch_group_async(group, queue, ^{ // 耗时操作2 }); // ... // 同步等待指定group执行完毕或超时 // 超时时间可以设为:DISPATCH_TIME_FOREVER-永远不超时;DISPATCH_TIME_NOW-很短时间内即超时; dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // 后续操作,如更新界面 // ...
dispatch_group_async/dispatch_group_notify搭配使用
// 创建队列和组 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); // 向队列中添加block并关联组 dispatch_group_async(group, queue, ^{ // 耗时操作1 }); dispatch_group_async(group, queue, ^{ // 耗时操作2 }); // ... // group中的block全部完成后添加block至queue;group可以不在queue中; // dispatch_group_notify是异步的; dispatch_group_notify(group, queue, ^{ // 耗时操作3 }); // 后续操作,如更新界面 // ...
3、dispatch_apply
作用:提交一个block至指定队列并循环调用多次,直到所有的调用都执行完毕函数才返回。使用方法例如:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 此方法会让主线程同步等待至所有循环调用block都执行完毕才返回 // 在这里,queue最好是传递一个并发队列才能发挥这个方法的最大优势 // index表示循环次数 dispatch_apply(5, queue, ^(size_t index) { }); // 后续操作,如更新界面 // ...
4、dispatch_barrier_async
作用:提交block到指定队列并异步执行,函数将在第一时间返回;如果这个队列是通过dispatch_queue_create方法创建的并发队列,则这个block要等到它队列前面的所有block执行完毕才会执行,排在这个block后面的block也要等到该block执行完毕才能执行;如果这个队列不是上述队列,则dispatch_barrier_async效果等同于dispatch_async。使用形式形如
dispatch_queue_t queue = dispatch_queue_create("com.zwxx.tiancai", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ // some code }); dispatch_barrier_async(queue, ^{ // some code }); dispatch_async(queue, ^{ // some code });
5、dispatch_once
作用:在应用程序的整个生命周期内只执行一次指定的block。常用它实现单例模式
+ (MyObject *)sharedMyObject { static MyObject *_singleton = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _singleton = [[MyObject alloc] init]; }); return _singleton; }