上一章, 我们了解到了GCD里的一些队列和任务的知识, 也实践了一下, 同时我们也对主队列的一些小情况了解了一下, 比如上一章讲到的卡线程的问题, 如果没有看的朋友可以去看看玩转iOS开发:iOS中的GCD开发(二)回顾一下.

这一章, 我们来讲讲关于GCD的一些其他小知识.

转载声明:如需要转载该文章, 请联系作者, 并且注明出处, 以及不能擅自修改本文.

GCD之间的通信

在我们日常的iOS开发里, 我们一般是会在主线程里刷新UI, 比如: 处理按钮的点击事件, 滚动视图, 拖拽视图等等操作.

但其他比较耗时的, 我们都会放在其他线程里进行操作, 比如: 上传/下载图片, 上传/下载文件等比较耗时的操作.

但这里还需要配合一下主线程来进行操作一番, 比如我们下载完图片之后, 需要回到主线程中刷新UI, 这时候我们就需要用到GCD之间的通信啦.

不懂? 那我们就来看看代码呗, 这里为了和上一章的工程重复, 我就新建过另一个工程, 取名为GCD-Up-Example, 机智如我~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)gcdCommunication {

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        for (NSInteger i = 0; i < 5; i++) {

            NSLog(@"第%ld次任务的主线程为: %@", i, [NSThread currentThread]);
} dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"回到主线程, 该线程为: %@", [NSThread currentThread]);
});
});
}
1
2
3
4
5
6
2017-08-05 18:47:11.942 GCD-Up-Example[15176:7745714] 第0次任务的主线程为: <NSThread: 0x60000006bb80>{number = 3, name = (null)}
2017-08-05 18:47:11.942 GCD-Up-Example[15176:7745714] 第1次任务的主线程为: <NSThread: 0x60000006bb80>{number = 3, name = (null)}
2017-08-05 18:47:11.943 GCD-Up-Example[15176:7745714] 第2次任务的主线程为: <NSThread: 0x60000006bb80>{number = 3, name = (null)}
2017-08-05 18:47:11.943 GCD-Up-Example[15176:7745714] 第3次任务的主线程为: <NSThread: 0x60000006bb80>{number = 3, name = (null)}
2017-08-05 18:47:11.944 GCD-Up-Example[15176:7745714] 第4次任务的主线程为: <NSThread: 0x60000006bb80>{number = 3, name = (null)}
2017-08-05 18:47:11.948 GCD-Up-Example[15176:7745541] 回到主线程, 该线程为: <NSThread: 0x60000006a1c0>{number = 1, name = main}

从结果里, 我们可以看到, 所有任务执行完之后, 就会回到主线程里了.

GCD的栅栏方法

有这么一个场景, 当我们需要进行异步操作两组数据时, 要求执行完第一组之后, 才能执行第二组, 那这个咋办咧?

GCD当中, 有一个方法可以解决这种需求, 也就是所谓的栅栏方法也称为屏障, 现在我们来撸一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- (void)gcdBarrier {

    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{

        NSLog(@"第一次任务的主线程为: %@", [NSThread currentThread]);
}); dispatch_async(queue, ^{ NSLog(@"第二次任务的主线程为: %@", [NSThread currentThread]);
}); dispatch_barrier_async(queue, ^{ NSLog(@"第一次任务, 第二次任务执行完毕, 继续执行");
}); dispatch_async(queue, ^{ NSLog(@"第三次任务的主线程为: %@", [NSThread currentThread]);
}); dispatch_async(queue, ^{ NSLog(@"第四次任务的主线程为: %@", [NSThread currentThread]);
});
}

大专栏  玩转iOS开发:iOS中的GCD开发(三)e>

通过结果, 我们可以看出, 在执行完第一次和第二次任务后, 会停留一下, 执行完这个栅栏方法之后, 才会继续执行之后的任务.

GCD的延迟方法

有时候, 需要一些延迟操作的场景, 那咋办咧? 放心~GCD也有提供这样子的方法, 并且延迟多少时间是由你说了算:

1
2
3
4
5
2017-08-05 19:00:44.494 GCD-Up-Example[15252:7757142] 第一次任务的主线程为: <NSThread: 0x60000007d580>{number = 3, name = (null)}
2017-08-05 19:00:44.494 GCD-Up-Example[15252:7757144] 第二次任务的主线程为: <NSThread: 0x60800007bb00>{number = 4, name = (null)}
2017-08-05 19:00:44.494 GCD-Up-Example[15252:7757144] 第一次任务, 第二次任务执行完毕, 继续执行
2017-08-05 19:00:44.495 GCD-Up-Example[15252:7757144] 第三次任务的主线程为: <NSThread: 0x60800007bb00>{number = 4, name = (null)}
2017-08-05 19:00:44.495 GCD-Up-Example[15252:7757142] 第四次任务的主线程为: <NSThread: 0x60000007d580>{number = 3, name = (null)}
1
2
3
4
5
6
7
8
9
- (void)gcdAfter {

    NSLog(@"我是一个路人");

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        NSLog(@"2秒后执行了.");
});
}
1
2
2017-08-05 19:07:20.039 GCD-Up-Example[15340:7766123] 我是一个路人
2017-08-05 19:07:22.225 GCD-Up-Example[15340:7766123] 2秒后执行了.
  • 看到结果, 我们就知道, 的确是延迟了两秒后才执行.
  • 如果你们不知道在哪里设置时间的话, 看这句代码里的2.0, 这就是设置时间了.

GCD只执行一次的方法

有时候, 我们需要创建一个类, 而这个类的某个方法只可以执行一次, 比如创建一个单例, 怎么用GCD解决呢?

既然能够提到这个问题, 那GCD肯定也会提供对方的方法嘛, 是吧~

1
2
3
4
5
6
7
8
- (void)gcdOne {

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
// 这里写只执行一次的任务就好了, 默认是线程安全, 所以不用担心
});
}

GCD的快速遍历方法

GCD当中, 也有一个类似for的遍历方法, 和for不同, 它几乎是同时遍历的.

1
2
3
4
5
6
7
8
9
- (void)gcdApply {

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_apply(5, queue, ^(size_t index) {

        NSLog(@"执行第%ld任务, 当前线程为: %@", index, [NSThread currentThread]);
});
}
1
2
3
4
5
2017-08-05 20:36:08.389 GCD-Up-Example[15555:7794146] 执行第0任务, 当前线程为: <NSThread: 0x608000074840>{number = 1, name = main}
2017-08-05 20:36:08.389 GCD-Up-Example[15555:7794186] 执行第1任务, 当前线程为: <NSThread: 0x60800007e2c0>{number = 3, name = (null)}
2017-08-05 20:36:08.389 GCD-Up-Example[15555:7794184] 执行第2任务, 当前线程为: <NSThread: 0x60800007e200>{number = 4, name = (null)}
2017-08-05 20:36:08.389 GCD-Up-Example[15555:7794183] 执行第3任务, 当前线程为: <NSThread: 0x60800007e300>{number = 5, name = (null)}
2017-08-05 20:36:08.389 GCD-Up-Example[15555:7794146] 执行第4任务, 当前线程为: <NSThread: 0x608000074840>{number = 1, name = main}

从结果里我们可以看到, 它几乎是同时遍历的, 而且要注意, 这个方法是开启了新线程来进行遍历的.

GCD的Queue Group

在某个场景下, 我们需要同时异步执行两个耗时的任务, 并且在执行完成后直接回到主线程, 这个怎么做呢?

GCD中, 有一个叫做队列组的东西(Queue Group), 它就可以满足我们这个场景需求了.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- (void)gcdQueueGroup {

    dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_async(group,
queue,
^{
// 执行第一个耗时的任务
}); dispatch_group_async(group,
queue,
^{
// 执行第二个耗时的任务
}); dispatch_group_notify(group,
dispatch_get_main_queue(),
^{
// 回到主线程
});
}

总结

GCD的一些常用知识基本到这里, 基本上已经哦了, 如果你还要更深入的去了解的话, 可以去GCD官方文档里查找一下你所需要的资料.

再多说一句话, 学习理论知识固然重要, 但要和实际开发使用挂钩, 不然光学不用, 等于空.

工程地址

项目地址: https://github.com/cainluo/iOS-Project-Example/tree/master/GCD-Up-Example

最新文章

  1. cookie欺骗
  2. Codeforces Round #383 (Div. 2) D. Arpa&#39;s weak amphitheater and Mehrdad&#39;s valuable Hoses(分组背包+dsu)
  3. lvs+keepalived+nginx实现高性能负载均衡集群
  4. 支持GPS的核心API
  5. 搞了台2ussd服务器
  6. 创建纯洁的TableViewCell
  7. matplotlib 绘制柱状图的几个例子
  8. Java学习笔记:语言基础
  9. 如何遍历json属性和动态添加属性
  10. 尽历磨难,搞定OPEN VSWITCH安装
  11. SharePoint 2010 -- .Net托管客户端模型简单示例
  12. Jetson TX1安装pyTorch
  13. 老男孩python学习自修第十二天【常用模块之生成随机数】
  14. Nginx在局域网中使用ip_hash负载均衡策略,访问全部分发到同一个后台服务器
  15. redis配置(redis.conf)
  16. Spring事务管理详解_基本原理_事务管理方式
  17. ubuntu下查看windows的 txt 文件乱码
  18. python 元组查找元素返回索引
  19. 抽象工厂模式( Abstract Factory )
  20. Windows程序设计(Charles Petzold)HELLOWIN程序实现

热门文章

  1. 8. docker image 的发布 与 docker registry 私有仓库
  2. is,==区别,编码转换
  3. vue中axios的post请求使用form表单格式发送数据
  4. iOS补位动画、沙漏效果、移动UITableViewCell、模拟贪吃蛇、拖拽进度等源码
  5. android打飞机游戏、MVP句子迷App、悬浮窗、RxJava+Retrofit、加载动画、定制计划App等源码
  6. JAVA并发思维导图
  7. Resin介绍及其使用配置
  8. VBE2014_Setup_20160709.rar
  9. Part-Linux-2
  10. SpringBoot常见面试题