GCD,全称Grand Central Dispath,是苹果开发的一种支持并行操作的机制。它的主要部件是一个FIFO队列和一个线程池,前者用来添加任务,后者用来执行任务。

GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行(但不保证一定先执行结束)。

通过与线程池的配合,dispatch queue分为下面两种:

  • Serial Dispatch Queue -- 线程池只提供一个线程用来执行任务,所以后一个任务必须等到前一个任务执行结束才能开始。
  • Concurrent Dispatch Queue -- 线程池提供多个线程来执行任务,所以可以按序启动多个任务并发执行。

1. Basic Management

我们可以通过dispatch_queue_cretae来创建队列,然后用dispatch_release释放。比如下面两段代码分别创建串行队列和并行队列:

dispatch_queue_t serialQ = dispatch_queue_create("eg.gcd.SerialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQ, ^{
// Code here
});
dispatch_release(serialQ); dispatch_queue_t concurrentQ = dispatch_queue_create("eg.gcd.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQ, ^{
// Code here
});
dispatch_release(concurrentQ);

而系统默认就有一个串行队列main_queue和并行队列global_queue:

dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t mainQ = dispatch_get_main_queue();

   通常,我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,避免UI阻塞,无法响应用户操作:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^{
// long-running task
dispatch_async(dispatch_get_main_queue(), ^{
// update UI
});
});

上面提到dispatch_async这个接口,用来提交blcok给指定queue进行异步执行。这个接口会在成功提交block后立即返回,然后继续执行下去。由于block是定义在栈上的,所以需要将其复制到堆上,见这里

与之相对应的是dispatch_sync接口,提交block以供同步执行。这个接口会等到block执行结束才返回,所以不需要复制block。So,如果在调用该接口在当前queue上指派任务,就会导致deadlock。维基百科上给了段示例代码:

dispatch_queue_t exampleQueue = dispatch_queue_create("com.example.unique.identifier", NULL );
dispatch_sync( exampleQueue,^{
dispatch_sync( exampleQueue,^{
printf("I am now deadlocked...\n");
});});
dispatch_release( exampleQueue );

如果追求的是并发,那么dispatch_sync有什么用呢?关于dispatch_sync的用途,SO上有讨论

2. Normal Control

  • dispatch_once

如果没有记错的话,在iOS Con 2012上,大众点评的同学分享了个Topic叫《iOS开发最佳实践》,开篇讲singleton实现的演进(怎么演进都有可以挑的刺),后面转折说要把精力放到用户看得到的地方。

如果把singleton和best practice放在一起,那么我很容易联想到dispatch_once这个函数,它可以保证整个应用程序生命周期中某段代码只被执行一次

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// code to be executed once
});
  • dispatch_after

有时候我们需要等个几秒钟然后做个动画或者给个提示,这时候可以用dispatch_after这个函数:

double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// code to be executed on the main queue after delay
});
  • dispatch_set_target_queue

通过dispatch_set_target_queue函数可以设置一个dispatch queue的优先级,或者指定一个dispatch source相应的事件处理提交到哪个queue上。

dispatch_set_target_queue(serialQ, globalQ);  
  • dispatch_apply

执行某个代码片段若干次。

dispatch_apply(, globalQ, ^(size_t index) {
// do sth. 10 times
});
  • dispatch group

Dispatch Group机制允许我们监听一组任务是否完成:

dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, concurrentQ, blk0);
dispatch_group_async(group, concurrentQ, blk1);
dispatch_group_async(group, concurrentQ, blk2);
dispatch_group_notify(group, mainQ, ^{
// update UI
});
dispatch_release(group);

或者说同步地等待一段时间看是否结束:

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
dispatch_group_wait(group, time);
  • dispatch_barrier_async

通过dispatch_barrier_async函数提交的任务会等它前面的任务执行结束才开始,然后它后面的任务必须等它执行完毕才能开始。

dispatch_async(concurrentQ, blk0);
dispatch_async(concurrentQ, blk1);
dispatch_barrier_async(concurrentQ, blk_barrier);
dispatch_async(concurrentQ, blk2);

原文链接:http://blog.csdn.net/jasonblog/article/details/7816999

最后,推荐一个神器。

内测宝

内测宝, 个人觉得比TestFlight更简单好用,开发者只需要简单把打好的ipa包上传上去,生成二维码,测试人员在手机上扫码二维码,就可以直接安装最新的测试版本了,好用的让人想哭。

iOS开发之GCD的更多相关文章

  1. iOS 开发之 GCD 不同场景使用

    header{font-size:1em;padding-top:1.5em;padding-bottom:1.5em} .markdown-body{overflow:hidden} .markdo ...

  2. iOS 开发之 GCD 基础

    header{font-size:1em;padding-top:1.5em;padding-bottom:1.5em} .markdown-body{overflow:hidden} .markdo ...

  3. iOS开发之GCD基础

    重新回顾.学习GCD.Block.先贴出一篇不错的讲解GCD基础使用的文章 原文地址:http://blog.csdn.net/aolan1108/article/details/17283415 做 ...

  4. iOS开发之GCD使用总结

    GCD是iOS的一种底层多线程机制,今天总结一下GCD的常用API和概念,希望对大家的学习起到帮助作用. GCD队列的概念 在多线程开发当中,程序员只要将想做的事情定义好,并追加到DispatchQu ...

  5. iOS开发之GCD总结

    直接贴出常用的函数,方便要用的时候直接使用. -------------     type 1 ---------------- 说明  : 创建一个dispatch_group_t,每次网络请求前先 ...

  6. iOS开发之GCD同步主线程、异步主线程

    /** 在主线程执行block */ + (void)gs_synExecuteOnMainThread:(void (^)(void))block { if ((nil == block) || ( ...

  7. iOS多线程开发之GCD(中篇)

    前文回顾: 上篇博客讲到GCD的实现是由队列和任务两部分组成,其中获取队列的方式有两种,第一种是通过GCD的API的dispatch_queue_create函数生成Dispatch Queue:第二 ...

  8. iOS多线程开发之GCD(死锁篇)

    上篇和中篇讲解了什么是GCD,如何使用GCD,这篇文章将讲解使用GCD中将遇到的死锁问题.有兴趣的朋友可以回顾<iOS多线程开发之GCD(上篇)>和<iOS多线程开发之GCD(中篇) ...

  9. iOS多线程开发之GCD(中级篇)

    前文回顾: 上篇博客讲到GCD的实现是由队列和任务两部分组成,其中获取队列的方式有两种,第一种是通过GCD的API的dispatch_queue_create函数生成Dispatch Queue:第二 ...

随机推荐

  1. undefined method `environment' for nil:NilClass when importing Bootstrap into rails

    今天做项目时往Gemfile里加了各gem, 然后bundle update了一下, 然后悲剧了,出现了undefined method `environment' for nil:NilClass ...

  2. LPC1768/1769之CAN控制器概述(附库函数下载地址)

    一.背景: 使用LPC1769来做CAN的收发,在此对使用LPC1769的CAN控制器进行收发做个总结和记录,以备下 次开发快速上手使用. 附:LPC1768/1769除了支持最高频率不同以外,其它基 ...

  3. oracle分区表知识

    在F5中查看执行计划的时候总是看到很多信息: range分区 执行计划中出现的: 分区表,按 n1 ,n2 分区 partition range single:访问单个分区 partition ran ...

  4. dex文件格式一

    一.生成dex文件 我们可以通过java文件来生成一个简单的dex文件 编译过程: 首先编写java代码如下: (1) 编译成 java class 文件 执行命令 : javac Hello.jav ...

  5. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

  6. Linux Swap分区设定

    因为准备在linux上面安装Oracle数据库,据说swap分区小于4G容易失败,天啦噜的我连swap分区是啥都不是非常清楚, 大概有个印象吧,但先搞大了再说. 测试证明Ubuntu14默认的swap ...

  7. Hbuilder MUI 选择器(Picker)设置默认选项

    mui 联动选择初始化很多人都遇到问题,就是setselectedvalue 不好用,实际上这个地方应该是有bug的 所以只能用setselectedindex 来实现 下面我是我的实现方式供大家参考 ...

  8. java导出生成word(类似简历导出)

    参考帖子: http://www.cnblogs.com/lcngu/p/5247179.html http://www.cnblogs.com/splvxh/archive/2013/03/15/2 ...

  9. spring mvc redis消息队列

    通常情况下,为了提高系统开发的灵活性和可维护度,我们会采用消息队列队系统进行解耦.下面是一个采用spring redis实现的消息队列实例,但此实例会由于网络延迟和阻塞等情况导致消息处理的延时,因而不 ...

  10. Fitbit Flex

    Fitbit Flex 使用 7月4日,收到了在美国亚马逊上海淘的Fitbit Flex.首先谈谈这价格,在美国亚马逊上购买时的价格是98美元,下订单过后没几天,京东开始首发出售,价格定在898元.相 ...