dispatch source和runLoop source都是用来监听事件的,你可以创建不同类型的dispatch source对象和runLoop source对象。dispatch source监测到事件产生时,会将事件处理器添加到dispatch queue ,稍后出队执行;runLoop source对象一般是NSObject对象,需要先按照某种模式加入到指定线程的runLoop中,利用runLoop这个循环来检测符合模式的事件是否产生,如果产生则向NSObject对象或其代理发送消息。dispatch source和runLoop source都是异步处理模式,你只要创建、设置好对象,就可以继续做其他事了。

Grand Central Dispatch支持以下类型的dispatch source:
Timer dispatch source:监测定期产生的事件
Signal dispatch source:监测UNIX信号到达的事件
Descriptor dispatch source:监测各种文件和socket科操作的事件:数据可读,数据可写
Filesystem node event source:监测文件在文件系统中被删除、移动、重命名、文件元数据信息改变的事件
Process dispatch source:监测进程相关的事件:当进程退出时,当进程发起fork或exec等调用,信号被递送到进程
Mach port dispatch source:监测Mach相关端口事件
Custom dispatch source:监测自己定义事件(需要自己触发该事件)

这里要理解“监测”的含义,我们都知道:在面向对象的编程世界里,对象不会主动监测某个事件,往往是被通知发生什么情况了或满足什么条件了,发生什么情况了或满足什么条件了就是”事件“产生了,哪个对象需要处理该事件,就要立即通知他,告诉他事件产生了。站在被通知者角度,说成监测某事件,便于理解。

创建Dispatch Source

使用 dispatch_source_create 函数创建dispatch source。当你创建一个dispatch source时,需要指定派发源类型(其实也就是监测的事件类型)、事件源(事件源是产生事件的本体,是一个底层系统数据类型的对象,例如基于描述符的dispatch source,需要传入打开的描述符;基于进程的dispatch source,需要传入目标程序的进程ID。)、事件源详情(一般用来描述具体事件)、dispatch queue、以及处理事件的代码(block或函数)。当事件发生时,dispatch source会提交你的block或函数到指定的queue去执行。和手工提交到queue的任务不同,dispatch source为应用提供连续的事件响应。除非你显式地取消,dispatch source会一直保留与dispatch queue的关联。只要相应的事件发生,就会提交关联的代码到dispatch queue去执行。

为了防止事件积压到dispatch queue,dispatch source实现了事件合并机制。如果新事件在上一个事件处理器出列并执行之前到达,dispatch source会将新旧事件的数据合并。根据事件类型的不同,合并操作可能会替换旧事件,或者更新旧事件的信息。

配置dispatch source

为dispatch source设置一个事件处理器(对于定时器源,还需要使用 dispatch_source_set_timer 函数设置定时器信息)
为dispatch source赋予一个取消处理器(可选)调用 dispatch_resume 函数开始处理事件由于dispatch source必须进行额外的配置才能被使用,dispatch_source_create 函数返回的dispatch source将处于挂起状态。此时dispatch source会接收事件,但是不会进行处理。这时候你可以安装事件处理器,并执行额外的配置。

你需要定义一个事件处理器来处理事件,可以是函数或block对象,并使用 dispatch_source_set_event_handler 或 dispatch_source_set_event_handler_f 设置事件处理器。事件到达时,dispatch source会提交你的事件处理器到指定的dispatch queue,由queue执行事件处理器。

事件处理器的代码负责处理所有到达的事件。如果事件处理器已经在queue中并等待出队执行,此时又来了一个新事件,dispatch source会合并这两个事件。事件处理器通常只能看到最新事件的信息,不过某些类型的dispatch source也能获得已经发生以及合并的事件信息。

如果事件处理器已经开始执行,一个或多个新事件到达,dispatch source会保留这些事件,直到前面的事件处理器完成执行。然后以新事件再次提交处理器到queue。
函数事件处理器有一个void*指针指向你使用dispatch_set_context方法设置的对象,没有返回值。Block事件处理器没有参数,也没有返回值。

// Block-based event handler  
    void (^dispatch_block_t)(void)  
       
    // Function-based event handler  
    void (*dispatch_function_t)(void *)

在事件处理器中,你可以从dispatch source中获得事件的信息,函数处理器可以直接使用参数指针,Block则必须自己捕获到dispatch source指针,一般block定义时会自动捕获到外部定义的所有变量。

dispatch_source_t mySource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, 
                                     myDescriptor, 0, myQueue); 
    dispatch_source_set_event_handler(mySource, ^{ 
       // Get some data from the source variable, which is captured 
       // from the parent context. 
       size_t estimated = dispatch_source_get_data(mySource); 
      
       // Continue reading the descriptor... 
    }); 
    dispatch_resume(mySource);

Block捕获外部变量允许更大的灵活性和动态性。当然,在Block中这些变量默认是只读的,虽然可以使用__block来修改捕获的变量,但是你最好不要在事件处理器中这样做。因为Dispatch source异步执行事件处理器,当事件处理器修改原始外部变量时,有可能这些变量已经不存在了。

在事件处理器中可以使用如下函数获取需要的信息:

dispatch_source_get_handle

这个函数返回dispatch source管理的底层系统数据类型,就是dispatch_source_create函数中第二个参数
对于描述符dispatch source,函数返回一个int,表示关联的描述符
对于信号dispatch source,函数返回一个int,表示最新事件的信号数值
对于进程dispatch source,函数返回一个pid_t数据结构,表示被监控的进程
对于Mach port dispatch source,函数返回一个 mach_port_t 数据结构

dispatch_source_get_data

这个函数返回值,取决于派发源类型
对于从文件中读取数据的描述符dispatch source,这个函数返回可以读取的字节数
对于向文件中写入数据的描述符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_create函数中第三个参数
对于进程dispatch source,函数返回dispatch source接收到的事件掩码,参考 dispatch_source_proc_flags_t 枚举类型
对于发送权利的Mach port dispatch source,函数返回期望事件的掩码,参考 dispatch_source_mach_send_flags_t 枚举类型
对于自定义 “或” 的dispatch source,函数返回用来合并数据值的掩码

设置取消处理器

取消处理器让你在dispatch soruce释放之前执行清理工作。多数类型的dispatch source不需要取消处理器,除非你对dispatch source有自定义行为需要在释放时执行。但是使用描述符或Mach port的dispatch source必须设置取消处理器,用来关闭描述符或释放Mach port。否则可能导致微妙的bug,这些结构体会被系统其它部分或你的应用在不经意间重用。你可以在任何时候设置取消处理器,但通常我们在创建dispatch source时就会设置取消处理器。使用 dispatch_source_set_cancel_handler 或 dispatch_source_set_cancel_handler_f 函数来设置取消处理器。
列如,下面设置”文件描述符派发源“的取消处理器:
    dispatch_source_set_cancel_handler(mySource, ^{ 
       close(myDescriptor); // Close a file descriptor opened earlier. 
    });

取消一个Dispatch Source
除非你显式地调用 dispatch_source_cancel 函数,否则dispatch source将一直保持活动;取消一个dispatch source只会停止将事件处理器入队,派发源依旧在监听事件,并且不能撤销。因此你通常在取消dispatch source后立即释放它。取消一个dispatch source是异步操作,调用 dispatch_source_cancel 之后,不会再有新的事件被处理,但是正在被dispatch source处理的事件会继续被处理完成。在处理完最后的事件之后,dispatch source会执行自己的取消处理器。
取消处理器是你最后的执行机会,在那里执行内存或资源的释放工作。例如描述符或mach port类型的dispatch source,必须提供取消处理器,用来关闭描述符或mach port

挂起和继续Dispatch Source
你可以使用 dispatch_suspend 和 dispatch_resume 临时地挂起和继续dispatch source的事件递送。这两个函数分别增加和减少dispatch 对象的挂起计数。因此,你必须每次 dispatch_suspend 调用之后,都需要相应的 dispatch_resume 才能继续事件递送。
挂起一个dispatch source期间,发生的任何事件都会被累积,直到dispatch source继续。但是不会递送所有事件,而是先合并到单一事件,然后再一次递送。例如你监控一个文件的文件名变化,就只会递送最后一次的变化事件。

修改目标Queue
在创建dispatch source时可以指定一个queue,用来执行事件处理器和取消处理器。不过你也可以使用 dispatch_set_target_queue 函数在任何时候修改目标queue。修改queue可以改变执行dispatch source事件的优先级。
修改dispatch source的目标queue是异步操作,dispatch source会尽可能快地完成这个修改。如果事件处理器已经进入queue并等待处理,它会继续在原来的Queue中执行。随后到达的所有事件的处理器都会在后面修改的queue中执行。
关联自定义数据到dispatch source
和Grand Central Dispatch的其它类型一样,你可以使用 dispatch_set_context 函数关联自定义数据到dispatch source。使用context指针存储事件处理器需要的任何数据。如果你在context指针中存储了数据,你就应该安装一个取消处理器,在dispatch source不再需要时释放这些context自定义数据。
如果你使用block实现事件处理器,你也可以捕获本地变量,并在Block中使用。虽然这样也可以代替context指针,但是你应该明智地使用Block捕获变量。因为dispatch source长时间存在于应用中,Block捕获指针变量时必须非常小心,因为指针指向的数据可能会被释放,因此需要复制数据或retain。不管使用哪种方法,你都应该提供一个取消处理器,在最后释放这些数据。
Dispatch Source的内存管理
Dispatch Source也是引用计数的数据类型,初始计数为1,可以使用 dispatch_retain 和 dispatch_release 函数来增加和减少引用计数。引用计数到达0时,系统自动释放dispatch source数据结构。
dispatch source的所有权可以由dispatch source内部或外部进行管理。外部所有权时,另一个对象拥有dispatch source,并负责在不需要时释放它。内部所有权时,dispatch source自己拥有自己,并负责在适当的时候释放自己。虽然外部所有权很常用,当你希望创建自主dispatch source,并让它自己管理自己的行为时,可以使用内部所有权。例如dispatch source应用单一全局事件时,可以让它自己处理该事件,并立即退出。

dispatch source理解相关推荐

  1. iOS之深入解析dispatch source的原理与功能

    一.dispatch source 和 runLoop source dispatch source 和 runLoop source 都是用来监听事件的,可以创建不同类型的 dispatch sou ...

  2. IOS并发编程指南:Dispatch Queue任务执行与Dispatch Source

    导读: 本文为读<Concurrency Programming Guide>笔记第三篇,在对OS X和iOS应用开发中实现任务异步执行的技术.注意事项.Operation与Dispatc ...

  3. Dispatch Source Timer

    1. 声明dispatch_source_t @property (nonatomic, strong) dispatch_source_t source; 这里必须强引用,否则计时器无法启动. 2. ...

  4. 我所理解的 iOS 并发编程

    作者:bool周 原文链接:我所理解的 iOS 并发编程 无论在哪个平台,并发编程都是一个让人头疼的问题.庆幸的是,相对于服务端,客户端的并发编程简单了许多.这篇文章主要讲述一些基于 iOS 平台的一 ...

  5. [OC学习笔记]Grand Central Dispatch

    一.GCD概要 (一)什么是GCD 什么是GCD?以下摘自苹果的官方说明. Grand Central Dispatch(GCD)是异步执行任务的技术之一.一般将应用程序中记述的线程管理用的代码在系统 ...

  6. GCD介绍(三): Dispatch Sources

    何为Dispatch Sources 简单来说,dispatch source是一个监视某些类型事件的对象.当这些事件发生时,它自动将一个block放入一个dispatch queue的执行例程中. ...

  7. GCD简介三:Dispatch Sources

    一.何为Dispatch Sources 简单来说,dispatch source是一个监视某些类型事件的对象.当这些事件发生时,它自动将一个block放入一个dispatch queue的执行例程中 ...

  8. live555 source

    Source和Sink:可以把source理解为发送端的流,sink理解为接受端.MediaSink是各种类型的Sink的基类,MediaSource是各种类型Source的基类,各种类型的流媒体格式 ...

  9. iOS之深入分析GCD的函数与队列以及多种组合使用

    一.GCD 简介 ① 什么是 GCD ? GCD 是 Apple 开发的一个多核编程的较新的解决方法: GCD 全称:Grand Central Dispatch,是纯 C 语言,提供非常多强大的函数 ...

  10. Android缩放比例公式,android开发 缩放到指定比例的尺寸

    一种通过matrix矩阵缩放: //使用Bitmap加Matrix来缩放 public static Drawable resizeImage(Bitmap bitmap, int w, int h) ...

最新文章

  1. HashCode和equal方法
  2. Android之程序反复回调一个类的解决办法
  3. 淘宝网商品管理?技术 ?
  4. 数据挖掘 python框架_8个最高效的Python爬虫框架
  5. SPOJ 4487 Can you answer these queries VI
  6. asp.net core 读取连接字符串
  7. python 配置文件对比_Python3实现配置文件差异对比脚本
  8. Python Django chartit 多报表显示
  9. -lc++ 和 添加 libc++.tbd 居然是等价的
  10. HDU 1155 Bungee Jumping(物理题,动能公式,弹性势能公式,重力势能公式)
  11. Java中Calendar基本使用--Comparator.comparing比较排序
  12. 基于DES和RSA算法自动分配密钥的加密聊天程序
  13. funny_upload
  14. Java通过freemaker实现健康报告生成(包含列表、列表合并列)
  15. 初识DataTable
  16. AutoML- NNI
  17. nginx二级域名配置阿里云免费SSL证书浏览器提示不安全
  18. 千锋教育威哥学Java——爆破专栏丨Spring Security系列教程之解决Spring Security环境中的跨域问题
  19. 程序员要怎样学习英语?
  20. PPT转PDF怎么转?这几种转换小技巧轻松拿捏

热门文章

  1. TP-LINK三层网管交换机通过console接口完成复位操作
  2. Android 自定义心形图片
  3. 北大青鸟 某百货商场当日他在消费积分最高的八名顾客,他们的积分分别是18,25,7,36,13,2,89,63.编写程序找出的积分及他在数组中的下标
  4. 技术成长-不积跬步无以至千里
  5. vue3的生命周期函数
  6. TCP之 select模型
  7. “四通一达”本一家,这家人是如何“承包”中国快递半壁江山的?
  8. 免费支持顺丰、四通一达、EMS等快递物流单号查询的开放接口?
  9. 根据手势拿到superview
  10. 青海省海西蒙古族藏族自治州谷歌高清卫星地图下载