现代系统通常提供异步接口,允许应用向系统提交请求,然后在系统处理请 求时应用可以继续处理其他事情。GCD 正是基于这个基本行为而设计,允许你 提交请求,并通过 block 和 dispatch queue 报告结果,而Dispatch Source替代了异步回调函数,来处理相关事件。
根据官方文档GCD支持以下Dispatch Source类型
DISPATCH_SOURCE_TYPE_DATA_ADD 自定义事件
DISPATCH_SOURCE_TYPE_DATA_OR 自定义事件
DISPATCH_SOURCE_TYPE_MACH_RECV 监听MACH响应事件
DISPATCH_SOURCE_TYPE_MACH_SEND 监听MACH响应事件
DISPATCH_SOURCE_TYPE_PROC 进程监听(退出,创建,fork 或 exec等调用)
DISPATCH_SOURCE_TYPE_READ 文件可读
DISPATCH_SOURCE_TYPE_WRITE 文件可写
DISPATCH_SOURCE_TYPE_SIGNAL UNIX信号到达时时响应
DISPATCH_SOURCE_TYPE_TIMER 定时器
DISPATCH_SOURCE_TYPE_VNODE 文件状态监听例如移动,删除,重命名等事件
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE 监听系统内存压力
创建Dispatch Source一般步骤
- 使用
dispatch_source_create
创建dispatch source - 配置dispatch source:
- 设置一个事件处理器
- 如果是定时器源,使用dispatch_source_set_timer函数设置定时器信息
- 为dispatch source赋予一个取消处理器(可选)
- 调用dispatch_resume 函数开始处理事件
定时器
示例代码:
函数会创建一个定时器
dispatch_source_t CreateDispatchTimer(uint64_t interval, uint64_t leeway,
dispatch_queue_t queue, dispatch_block_t block)
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if (timer) {
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);//设置定时器信息
dispatch_source_set_event_handler(timer, block);//设置处理器
dispatch_resume(timer); //调用以便函数开始处理事件
}
return timer;
}
可捕获的事件类型
//调用示例
dispatch_source_t source_t = CreateDispatchTimer(30ull * NSEC_PER_SEC, 1ull * NSEC_PER_SEC, dispatch_get_global_queue(0, 0), ^{
NSLog(@"executing");
});
uintptr_t handle = dispatch_source_get_handle(source_t);
unsigned long data = dispatch_source_get_data(source_t);
unsigned long mask = dispatch_source_get_mask(source_t);
NSLog(@"done");
函数 | 描述 |
---|---|
dispatch_source_get_handle | 这个函数返回 dispatch source 管理的底层系 统数据类型。 |
对于描述符 dispatch source,函数返回一个 int,表示关联的描述符 | |
对于信号 dispatch source,函数返回一个 int 表示最新事件的信号数值 | |
对于进程 dispatch source,函数返回一个 pid_t 数据结构,表示被监控的进程 | |
对于 Mach port dispatch source,函数返回一 个 mach_port_t 数据结构 | |
对于其它 dispatch source,函数返回的值未 定义 | |
dispatch_source_get_data | 这个函数返回事件关联的所有未决数据。 |
对于从文件中读取数据的描述符 dispatch source,这个函数返回可以读取的字节数 | |
对于监控文件系统活动的描述符 dispatch source,函数返回一个常量,表示发生的事 件类型,参考 dispatch_source_vnode_flags_t 枚举类型 | |
对于进程 dispatch source,函数返回一个常 量,表示发生的事件类型,参考 dispatch_source_proc_flags_t 枚举类型 | |
对于 Mach port dispatch source,函数返回一 个常量,表示发生的事件类型,参考dispatch_source_machport_flags_t 枚举 类型 | |
对于自定义 dispatch source,函数返回从现 有数据创建的新数据,以及传递给 dispatch_source_merge_data 函数的新数 据。 | |
dispatch_source_get_mask | 这个函数返回用来创建 dispatch source 的事 件标志 |
对于进程 dispatch source,函数返回 dispatch source 接收到的事件掩码,参考 dispatch_source_proc_flags_t 枚举类型 | |
对于发送权利的 Mach port dispatch source, 函数返回期望事件的掩码,参考 dispatch_source_mach_send_flags_t 枚举 类型 | |
对于自定义 “或” 的 dispatch source,函数返 回用来合并数据值的掩码。 |
Dispatch Source实例
- 分派源
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD,
0, 0, dispatch_get_main_queue());
__block long totalComplete = 0;
//在同一时间,只有一个处理方法块的实例被分派,
//如果这个处理方法还未执行完毕,另一个事件就发生了,
//事件会以指定方式(ADD 或者 OR)进行累积.
//处理时间最终执行时,计算后的数据通过dispatch_source_get_data 获取
dispatch_source_set_event_handler(source, ^{
long value = dispatch_source_get_data(source);
totalComplete += value;
NSLog(@"totalComplete: %ld", totalComplete);
});
//恢复源
dispatch_resume(source);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0);
// 恢复源后通过 dispatch_source_merge_data 向分派源发送事件
dispatch_async(queue, ^{
for (int i = 0; i <= 100; ++i) {
dispatch_source_merge_data(source, 1);
usleep(20000);
}
});
- 定时器源
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
//do something
});
dispatch_resume(timer);
- 从描述符中读取数据
dispatch_source_t ReadContentsFromFile(const char* filename)
{
// 获取文件指针
int fd = open(filename, O_RDONLY);
if (fd == -1) {//获取失败
return NULL;
}
// 设置文件描述符状态旗标,防止阻塞读取操作
fcntl(fd, F_SETFL, O_NONBLOCK);
// 获取全局队列,优先级默认
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
if (!readSource) {
close(fd);
return NULL;
}
// 设置事件响应
dispatch_source_set_event_handler(readSource, ^{
size_t estimatedSize = dispatch_source_get_data(readSource) + 1;
char *buffer = (char *)malloc(estimatedSize);
if (buffer) {
ssize_t actual = read(fd, buffer, (estimatedSize));
// do something with buffer
free(buffer);
//读取完毕后
// dispatch_source_cancel(readSource);
}
});
// 取消事件
dispatch_source_set_cancel_handler(readSource, ^{close(fd);});
// 唤醒source
dispatch_resume(readSource);
return readSource;
}
- 向描述符写入数据
dispatch_source_t WriteDataToFile(const char* filename)
{
// 获取文件指针
int fd = open(filename);
if (fd == -1)//获取失败
return NULL;
// 设置文件描述符状态标旗,读文件时候阻塞
fcntl(fd, F_SETFL);
// 获取全局队列,优先级默认
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 创建source
dispatch_source_t writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
if (!writeSource) {
close(fd);
return NULL;
}
// 设置事件响应
dispatch_source_set_event_handler(writeSource, ^{
size_t estimatedSize = dispatch_source_get_data(writeSource) + 1;
char *buffer = (char *)malloc(estimatedSize);
if (buffer) {
ssize_t actual = read(fd, buffer, (estimatedSize));
// do something with buffer
free(buffer);
}
//读取完毕后
dispatch_source_cancel(readSource);
});
// 取消事件
dispatch_source_set_cancel_handler(writeSource, ^{close(fd);});
// 唤醒source
dispatch_resume(writeSource);
return writeSource;
}
- 监控文件系统对象
dispatch_source_t MonitorFileNameChange(const char* filename)
{
// 文件只读
int fd = open(filename, O_EVTONLY);
if (fd == -1) return NULL;//获取失败
// 获取全局队列,优先级默认
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 创建source
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_RENAME, queue);
if (source)
{
// 获取文件名长度
int length = strlen(filename);
char* newString = (char*)malloc(length + 1);
newString = strcpy(newString, filename);
dispatch_set_context(source, newString);
// 设置事件响应
dispatch_source_set_event_handler(source, ^{
const char* oldFilename = (char*)dispatch_get_context(source);
// dosomething
});
// 清理操作
dispatch_source_set_cancel_handler(source, ^{
char* fileStr = (char*)dispatch_get_context(source);
free(fileStr);
close(fd);
});
// 恢复source
dispatch_resume(source);
}
return nil;
}
- 监控进程
dispatch_source_t MonitorProcess()
{
// 获取进程pid
pid_t pid = getppid();
// 获取全局队列,优先级默认
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 创建source
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC , pid, DISPATCH_PROC_EXIT, queue);
if (source)
{
dispatch_source_set_event_handler(source, ^{
// do something with process exit event
dispatch_source_cancel(source);
// dispatch_release(source);
});
dispatch_resume(source);
}
return source;
}