Dispatch Source
by
目录
- 概述
- 事件与种类
- 使用 Dispatch Source
概述
iOS 中有两种 Source,一种是 Run Loop Source ,一种是 Dispatch Source。
Source 可以理解为产生事件的地方,Source 产生事件,然后 Source 的回调函数负责 处理这些事件。
在 Run Loop 中, Run Loop Source 产生事件,之后唤醒 Run Loop, Run Loop 便执行该 Source 的回调函数。
Dispatch Source 也会产生一些特定的事件,当这些事件发生的时候,其回调的 block 会自动加入到 对应的 dispatch queue 中。
事件与种类
Dispatch Source 监控的事件主要有以下几种:
- Timer dispatch sources generate periodic notifications.
- Signal dispatch sources notify you when a UNIX signal arrives.
- Descriptor sources notify you of various file- and socket-based operations, such as:
- When data is available for reading
- When it is possible to write data
- When files are deleted, moved, or renamed in the file system
- When file meta information changes
- Process dispatch sources notify you of process-related events, such as:
- When a process exits
- When a process issues a fork or exec type of call
- When a signal is delivered to the process
- Mach port dispatch sources notify you of Mach-related events.
- Custom dispatch sources are ones you define and trigger yourself.
对应着系统定义的 Dispatch Source 种类:
- DISPATCH_SOURCE_TYPE_TIMER 定时器
- DISPATCH_SOURCE_TYPE_SIGNAL 接收到 UNIX 信号
- DISPATCH_SOURCE_TYPE_READ 文件可读
- DISPATCH_SOURCE_TYPE_WRITE 文件可写
- DISPATCH_SOURCE_TYPE_VNODE 文件系统有变更
- DISPATCH_SOURCE_TYPE_PROC 与进程相关的事件
- DISPATCH_SOURCE_TYPE_MACH_SEND Mach 端口发送事件
- DISPATCH_SOURCE_TYPE_MACH_RECV Mach 端口接收事件
- DISPATCH_SOURCE_TYPE_DATA_ADD 用户自定义的事件-变量相加
- DISPATCH_SOURCE_TYPE_DATA_OR 用户自定义的事件-变量相或
这些事件都是来自于 XNU 内核中,kqueue 是用来处理这些事件的最好的一种方法,Dispatch Source 就是对 kqueue 的封装。
使用 Dispatch Source
使用 Dispatch Source 一般分为以下几步:
- 创建 Dispatch Source
- 配置 Dispatch Source
- 启动 Dispathc source
- 手动或自动发送 Dispatch Source 事件
自定义 Dispatch Source
首先创建并配置 Dispatch Sourcce
self.count = 0;
dispatch_queue_t queue = dispatch_get_main_queue();
self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue);//创建 Dispatch Source,种类为DISPATCH_SOURCE_TYPE_DATA_ADD,即获取到的变量会相加
dispatch_source_set_event_handler(self.source, ^{
UInt64 value = dispatch_source_get_data(self.source);
self.count += value;
NSLog(@"n = %ld",(long)self.count);
});//配置 Dispatch Source 的回调 block,即当收到该 Source 事件时候,就把该 block 追加到对应的queue中
dispatch_resume(self.source); //启动 Source, Source 默认是 suspend 的,需要手动启动
发送 Dispatch Source 事件
- (IBAction)buttonDidClicked:(id)sender {
self.count = 0.0;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT , 0);
for (NSInteger i = 0; i < 100; i++) {
dispatch_async(queue, ^{
dispatch_source_merge_data(self.source, 1);//发送 Source 事件
sleep(1);
});
}
}
之后,我们点击按钮之后,就会通过全局并发队列 发送 100 次 Source 事件,不过并不会 回调 100 次 回调 Block, 这是因为对应的 队列在接收到 Source 事件之后,假如队列处于空闲状态,就会执行对应的 回调 Block,假如队列处于 busy 状态,该事件就会和后面的一系列同种事件通过一定的方式被合并起来(此例中是按照相加的方式),等到队列空闲的时候再执行。
Dispatch Source Timer
利用 Dispatch Source 的 DISPATCH_SOURCE_TYPE_TIMER 类型,我们可以创建一个 跨线程的 定时器(我们平时使用的 NSTimer 是基于 Run Loop 的 timer 事件,只能在对应的线程里触发)
dispatch_queue_t queue = dispatch_get_main_queue();
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);//创建一个 timer;
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);//配置 timer,从现在起,每两秒在主线程触发一次,精度为0s
dispatch_source_set_event_handler(self.timer, ^{
NSLog(@"%ld", self.count++);
});//timer 触发之后的回调 block
dispatch_resume(self.time); //启动 timer
参考资料
Subscribe via RSS