App开发流程之使用GCD
GCD即为Grand Central Dispatch的缩写,是一种主要用于异步处理任务的安全的高性能解决方案。
在此不对比其他异步处理技术,只记录GCD的使用及说明。
先记录一些必要的概念:线程,同步,异步,并行队列,串行队列
线程:程序中任务执行流的最小单元。一个应用程序,一般存在一个进程(拥有独立内存空间),而每个进程可以有多个线程,即多个任务执行流,类似于工厂车间的流水线。每个应用程序至少存在一个线程,即为主线程,作为唯一可以控制UI的线程。
同步:主要指多个任务在同一个线程上依次执行。
异步:主要指多个任务在不同线程上同时执行。
队列:C语言中的队列指先进先出(FIFO)的数据结构,与栈的先进后出(FILO)相反。在GCD中分DISPATCH_QUEUE_SERIAL(串行队列)和DISPATCH_QUEUE_CONCURRENT(并行队列)。
并行队列:主要指队列中多个任务可以同时执行。
串行队列:主要指队列中多个任务只能依次执行。
逐个记录重要的方法:
dispatch_queue_t dispatch_get_main_queue(void)
获取主线程关联的队列。主队列是串行队列,该队列中任务都将由主线程执行,UI相关的操作必须加入此队列。
dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);
获取全局通用的并行队列。第一个参数一般指定优先级,有如下选项:
DISPATCH_QUEUE_PRIORITY_HIGH
DISPATCH_QUEUE_PRIORITY_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW
DISPATCH_QUEUE_PRIORITY_BACKGROUND
第二个参数,用于标记,一般传入0即可。
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
自定义创建一个派发队列。第一个参数作为描述,例如"newcustomqueue";第二个参数一般指定队列内任务是串行(DISPATCH_QUEUE_SERIAL)还是并行(DISPATCH_QUEUE_CONCURRENT)类型。
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
将一个block加入队列,异步执行。
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
将一个block加入队列,同步执行。
使用和测试以上方法
定义了几个队列:
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t customSerialQueue = dispatch_queue_create("customserialqueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t customConcurrentQueue = dispatch_queue_create("customconcurrentqueue", DISPATCH_QUEUE_CONCURRENT);
使用示例一:



总结:
上述代码,在同一次运行中,执行了多次,其中两次截图如上。
1.主队列必定在主线程中执行
2.在主线程中,使用dispatch_async异步执行非主队列中任务,将产生新的子线程
使用示例二:

总结:
主线程卡死。该方法在block执行完之前不会return,而block也是在当前线程执行,所以互相等待,造成死锁。
在主线程中使用同步执行主队列任务,将死锁。
使用示例三:


总结:
子线程卡死,UI依然可以操作。
综合示例二和三,得出:在执行(同步或者异步)串行队列的线程中再使用dispatch_sync同步执行当前串行队列,将造成线程死锁。
使用示例四:


总结:
调用dispatch_sync将在当前线程上依次执行添加的任务,不管是否在同一队列中,也不管队列类型。
使用示例五:
LOG(@"测试GCD dispatch_async混合dispatch_sync");
LOG(@"mainThread : %@", [NSThread mainThread]); dispatch_async(customSerialQueue, ^{
LOG(@"level 1 dispatch_async No.1 customSerialQueue : %@", [NSThread currentThread]); dispatch_async(customSerialQueue, ^{
LOG(@"level 2 dispatch_async No.1 customSerialQueue : %@", [NSThread currentThread]);
}); dispatch_async(customSerialQueue, ^{
LOG(@"level 2 dispatch_async No.2 customSerialQueue : %@", [NSThread currentThread]);
}); dispatch_async(customSerialQueue, ^{
LOG(@"level 2 dispatch_async No.3 customSerialQueue : %@", [NSThread currentThread]);
}); //==============================
dispatch_async(customConcurrentQueue, ^{
LOG(@"level 2 dispatch_async No.4 customConcurrentQueue : %@", [NSThread currentThread]);
}); dispatch_async(customConcurrentQueue, ^{
LOG(@"level 2 dispatch_async No.5 customConcurrentQueue : %@", [NSThread currentThread]);
}); dispatch_async(customConcurrentQueue, ^{
LOG(@"level 2 dispatch_async No.6 customConcurrentQueue : %@", [NSThread currentThread]);
}); //==============================
dispatch_sync(customConcurrentQueue, ^{
LOG(@"level 2 dispatch_sync No.7 customConcurrentQueue : %@", [NSThread currentThread]);
}); dispatch_sync(customConcurrentQueue, ^{
LOG(@"level 2 dispatch_sync No.8 customConcurrentQueue : %@", [NSThread currentThread]);
}); dispatch_sync(customConcurrentQueue, ^{
LOG(@"level 2 dispatch_sync No.9 customConcurrentQueue : %@", [NSThread currentThread]);
});
}); dispatch_async(customConcurrentQueue, ^{
LOG(@"level 1 dispatch_async No.2 customConcurrentQueue : %@", [NSThread currentThread]); dispatch_sync(customSerialQueue, ^{
LOG(@"level 2 dispatch_sync No.10 customSerialQueue : %@", [NSThread currentThread]);
}); dispatch_sync(customSerialQueue, ^{
LOG(@"level 2 dispatch_sync No.11 customSerialQueue : %@", [NSThread currentThread]);
}); dispatch_sync(customSerialQueue, ^{
LOG(@"level 2 dispatch_sync No.12 customSerialQueue : %@", [NSThread currentThread]);
}); //==============================
dispatch_async(customConcurrentQueue, ^{
LOG(@"level 2 dispatch_async No.13 customConcurrentQueue : %@", [NSThread currentThread]);
}); dispatch_async(customConcurrentQueue, ^{
LOG(@"level 2 dispatch_async No.14 customConcurrentQueue : %@", [NSThread currentThread]);
}); dispatch_async(customConcurrentQueue, ^{
LOG(@"level 2 dispatch_async No.15 customConcurrentQueue : %@", [NSThread currentThread]);
}); //==============================
dispatch_async(customSerialQueue, ^{
LOG(@"level 2 dispatch_async No.16 customSerialQueue : %@", [NSThread currentThread]);
}); dispatch_async(customSerialQueue, ^{
LOG(@"level 2 dispatch_async No.17 customSerialQueue : %@", [NSThread currentThread]);
}); dispatch_async(customSerialQueue, ^{
LOG(@"level 2 dispatch_async No.18 customSerialQueue : %@", [NSThread currentThread]);
});
});

总结:
1.串行队列customSerialQueue,只关注任务加入的先后顺序,不管是同步还是异步执行,总体顺序不变
2.多个同步执行的同一串行队列,如果加入了另一个执行队列,他们的执行线程相同
3.多个异步执行的同一串行队列,如果加入了另一个执行队列,他们的执行线程相同
4.综合上述,使用dispatch_sync,一定是在当前线程执行;使用dispatch_async,不一定产生新的子线程,如果在同一级下,执行串行队列,将使用已存在的同一线程。
5.多个嵌套的异步执行并行队列,可能使用已存在的闲置线程
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
该方法与dispatch_async类似,将block加入队列异步执行。注意当轮到该block执行时候,唯一异步执行,执行完毕后才会执行其他任务。所以只有加入并行队列,该方法才有意义。特别适用于加锁操作。
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
将block将入队列,延迟一定时间后异步执行。
使用示例:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//code to be executed after a specified delay
});
表示在5秒以后,将block加入主队列异步执行。
void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));
将block加入队列指定次数。队列可以是并行的,所以block执行可以为并行。size_t表示加入时的索引。
测试代码:
dispatch_apply(10, globalQueue, ^(size_t index) {
LOG(@"dispatch_apply : %zu", index);
});
-- ::33.023 base[:] dispatch_apply :
-- ::33.023 base[:] dispatch_apply :
-- ::33.023 base[:] dispatch_apply :
-- ::33.024 base[:] dispatch_apply :
-- ::33.024 base[:] dispatch_apply :
-- ::33.024 base[:] dispatch_apply :
-- ::33.024 base[:] dispatch_apply :
-- ::33.024 base[:] dispatch_apply :
-- ::33.024 base[:] dispatch_apply :
-- ::33.024 base[:] dispatch_apply :
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
只执行block中代码一次。特别适用于单例模式。
使用示例:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
});
void dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);
该方法将加入队列的block分组管理,特别适用于多方法并行,最后整合全部结果。第一个参数由如下方法得到:
dispatch_group_t dispatch_group_create(void);
void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);
该方法用于group中所有任务都完成后,回调block内容。
示例代码:
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, globalQueue, ^{
LOG(@"dispatch_group_async : 1");
});
dispatch_group_async(group, globalQueue, ^{
LOG(@"dispatch_group_async : 2");
});
dispatch_group_async(group, globalQueue, ^{
LOG(@"dispatch_group_async : 3");
});
dispatch_group_async(group, globalQueue, ^{
LOG(@"dispatch_group_async : 4");
});
dispatch_group_notify(group, globalQueue, ^{
LOG(@"dispatch_group_async : completion");
});
-- ::15.490 base[:] dispatch_group_async :
-- ::15.490 base[:] dispatch_group_async :
-- ::15.490 base[:] dispatch_group_async :
-- ::15.490 base[:] dispatch_group_async :
-- ::15.491 base[:] dispatch_group_async : completion
以上记录了GCD的常见使用方法和示例代码。
App开发流程之使用GCD的更多相关文章
- 20个可以帮你简化iOS app开发流程的工具
这里推荐20个可以帮你简化iOS app开发流程的工具.很多开发者都使用过这些工具,涉及原型和设计.编程.测试以及最后的营销,基本上涵盖了整个开发过程. 原型和设计 有了一个很好的创意后,你要做的不是 ...
- iOS开发之工具篇-20个可以帮你简化移动app开发流程的工具
如果想进入移动app开发这个领域,你总能从别的开发者或者网上或者书上找到各种各样的方法和工具,对于新手来说,还没有摸清门路就已经陷入迷茫了.这里推荐20个可以帮你简化app开发流程的工具.很多开发者都 ...
- app开发流程有哪些
app开发流程是需求方和供求方相互协调的过程,一般分为需求分析.功能设计.功能实现.项目测试.上线等几个步骤,下面我们就来一起看看ytkah团队进行app开发各个流程主要做哪些事情,让您对app开发设 ...
- 深度讲解智能硬件手机APP开发流程
常州做APP开发公司紫竹云科技分析,智能硬件产品的软件开发,除了APP和后台之外还有一个固件端的开发,由于固件是要运行产品上的,不过此时的硬件也是刚开始进行研发,所以是无法提供硬件来运行固件的.因此在 ...
- APP开发流程
1.申请一个开发者账号: 2. App的idea形成: 3. App的主要功能设计: 4. App的大概界面构思和设计(使用流程设计): 5. 大功能模块代码编写: 6. 大概的界面模块编写: 7. ...
- iOS 直播类APP开发流程分解:
1 . 音视频处理的一般流程: 数据采集→数据编码→数据传输(流媒体服务器) →解码数据→播放显示1.数据采集:摄像机及拾音器收集视频及音频数据,此时得到的为原始数据涉及技术或协议:摄像机:CCD.C ...
- App开发流程之源代码Git管理
base项目已经可以编译运行了,只不过没有实际功能而已.继续完善base项目前,我们需要考虑一下代码管理的事情了. 不管是一个人开发还是一个团队开发,对源代码进行版本管理是必须的,任何人对代码的的任何 ...
- angular based app开发流程
整理user story mock UI,生成满足上述user story的原型界面 根据上述UI,整理出data model(适用于后端和angular的数据模型) 后端CRUD开发,形成REST ...
- iOS 直播类APP开发流程解析
1 . 音视频处理的一般流程: 数据采集→数据编码→数据传输(流媒体服务器) →解码数据→播放显示1.数据采集:摄像机及拾音器收集视频及音频数据,此时得到的为原始数据涉及技术或协议:摄像机:CCD.C ...
随机推荐
- 【Android】你应该知道的调试神器----adb
最近跟着一个前辈在做TV应用,因为不能通过usb连接调试,接触到了adb,突然间觉得自己似乎发现了另外一个世界,借助adb shell命令对应用进行调试,简直方便得不行.更重要的是,这是命令行操作啊! ...
- 采用Kettle分页处理大数据量抽取任务
作者:Grey 原文地址: http://greyzeng.com/2016/10/31/big-data-etl/ 需求: 将Oracle数据库中某张表历史数据导入MySQL的一张表里面. 源表(O ...
- 使用CSS3对链接颜色与下划线进行优化
效果: 代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...
- 【原创】kafka producer源代码分析
Kafka 0.8.2引入了一个用Java写的producer.下一个版本还会引入一个对等的Java版本的consumer.新的API旨在取代老的使用Scala编写的客户端API,但为了兼容性 ...
- 选择排序---堆排序算法(Javascript版)
堆排序分为两个过程: 1.建堆. 堆实质上是完全二叉树,必须满足:树中任一非叶子结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字. 堆分为:大根堆和小根堆,升序排序采用大根堆,降序排序 ...
- 利用chrome调试JavaScript代码
看见网上很多人问怎么用chrome调试JavaScript代码,我也对这个问题抱着疑问,但是没有找到一篇能用的中文文章(可能我的google有问题),也不知道怎么点出一篇E文的,感觉作者写得不错,所以 ...
- C#编程总结(一)序列化
C#编程总结(一)序列化 序列化是将对象状态转换为可保持或传输的格式的过程.与序列化相对的是反序列化,它将流转换为对象.这两个过程结合起来,可以轻松地存储和传输数据. 几种序列化技术: 1) ...
- SQLServer中游标是如何处理数据的?
游标(Cursor)是处理数据的一种方法,为了查看或者处理结果集中的数据,游标提供了在结果集中一次以行或者多行前进或向后浏览数据的能力.我们可以把游标当作一个指针,它可以指定结果中的任何位置,然后允许 ...
- Nhibernate的第一个实例
第一个NhIbernate程序 1.目的: a) 链接到oracle数据库 b) 增删改 c) 基本查询.sql查询 d) 视图查询 e) 使用存储过程 f) 多表查询.级联查询 g) 级联增删改 2 ...
- Eclipse设置风格
如果觉得Eclipse的颜色太刺眼,可以修改背景与字体颜色,方法如下: (1)到http://eclipsecolorthemes.org/下载主题文件,可以选择xml文件或者epf文件: (2)Ec ...