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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,561评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,218评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,162评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,470评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,550评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,806评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,951评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,712评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,166评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,510评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,643评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,306评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,930评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,745评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,983评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,351评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,509评论 2 348

推荐阅读更多精彩内容

  • Dispatch Sources 现代系统通常提供异步接口,允许应用向系统提交请求,然后在系统处理请求时应用可以继...
    好雨知时节浩宇阅读 3,813评论 2 5
  • 支持原创 现代系统通常提供异步接口,允许应用向系统提交请求,然后在系统处理请求时应用可以继续处理自己的事情。Gra...
    John_LS阅读 3,570评论 3 2
  • 关于Dispatch Source Dispatch Source是GCD中的一种基本数据类型,从字面意思可称其为...
    杭研融合通信iOS阅读 3,547评论 1 8
  • Dispatch Sources 现代系统通常提供异步接口,允许应用向系统提交请求,然后在系统处理请求时应用可以继...
    YangPu阅读 303评论 0 0
  • 如果可以的话,我只想随便一间屋子,独自呆着。想去哪里去哪里。 我明明喜欢的是到处走,为什么要固定在一个地方。我喜欢...
    明天飞阅读 123评论 0 0