IOS Dispatch Source 笔记

代码地址(仅供参考)

现代系统通常提供异步接口,允许应用向系统提交请求,然后在系统处理请 求时应用可以继续处理其他事情。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一般步骤
  1. 使用dispatch_source_create创建dispatch source
  2. 配置dispatch source:
    • 设置一个事件处理器
    • 如果是定时器源,使用dispatch_source_set_timer函数设置定时器信息
  3. 为dispatch source赋予一个取消处理器(可选)
  4. 调用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;
}

你可能感兴趣的:(IOS Dispatch Source 笔记)