dispatch timer就是一类dispatch source:DISPATCH_SOURCE_TYPE_TIMER,并非是一个单独的timer。还有DISPATCH_SOURCE_TYPE_DATA_ADD等共10类。这10类作用基本都是监听事件。只是用法不同,timer是固定时间触发监听事件。
DISPATCH_SOURCE_TYPE_DATA_ADD类型的源是在调用dispatch_source_merge_data的时候触发事件,而且它有个很有意思的特点就是当同一时间,一个事件的的触发频率很高时,Dispatch Source会将这些事件以ADD的方式进行累积,然后等系统空闲时最终处理。如果触发频率比较零散,那么Dispatch Source会将这些事件分别响应。
而且这些源都基本的操作都是:1. 创建;2. 分发;3. 挂起;4,取消。
下面开始详细看下dispatch timer的使用。
创建timer
创建timer的代码如下:
// 创建timer
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 开始时间
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, 1.0*NSEC_PER_SEC);
// 间隔时间
dispatch_time_t interval = 2.0*NSEC_PER_SEC;
dispatch_source_set_timer(timer,start,interval,1000ull);
注意,在ARC中dispatch_source_t和普通的OC对象一样使用,所以timer使用时不要是局部变量,因为局部变量会立即释放。要注意timer的生命周期,这个和NSTimer一样。需要注意的是dispatch timer中用到的时间都是纳秒,即NSEC_PER_SEC。这里要注意的是dispatch timer没有repect参数,如果只想触发一次需要把间隔时间设置成DISPATCH_TIME_FOREVER。
事件处理
dispatch timer的处理分为两种:block和函数指针;
// block形式
dispatch_source_set_event_handler(timer, ^{
// 这里是一个无参数无返回值的block
});
上面是block形式,使用时也要注意循环引用。这个和NSTimer是一样的。仔细看方法名可以注意到,该方法名与timer是没关系的,也就是其他类型的源想要设置handler也是这样的。
// 设置跟随timer的context
void *context = NULL;
dispacth_set_context(timer,context);
// C类型的回调方法
void funcPointer1(void*arg){//...}
void funcPointer2(void*arg){//...}
// 设置回调方法
dispach_source_set_event_handler_f(timer,funcPointer1);
dispach_source_set_cancel_event_handler_f(timer,funcPointer2);
上面是函数指针的形式。要比block复杂一点。从下往上看,可以看到可以设置两个回调方法,分别是事件触发和事件取消时的方法。回调方法是一个C的函数指针。函数指针类型如funcPointer1所示。跟随timer的context是block没有的重要的功能。该context会在事件触发时传递给funcPointer1方法。context是一个void*的指针,可以添加任意多的内容。但是注意的是在ARC下结构体内部不能有对象。注意context可能会造成循环引用。
分发事件与停止事件
事件分发和事件触发在这是两个完全不同的事。比如timer的事件触发是底层mk_timer触发的。事件触发后能不能分发是由GCD决定的。再比如DISPATCH_SOURCE_TYPE_DATA_ADD是我们调用dispatch_source_merge_data触发的,能不能分发也是有GCD决定的。
// 启动分发事件
dispatch_resume(source);
// 暂停分发事件
dispacth_suspend(source);
// 取消事件,也就是停止监听事件
dispatch_cancel(source);
dispatch_resume事件想要被处理就必须调用该方法,该方法可以理解成是事件分发的开关。dispatch_suspend会暂停事件分发。暂停期间,所有的事件都会被丢弃,也就是在此开始时这期间的事件不会被处理。dispatch_cancel会停止接收时间,无法再开始。如果强行掉resumen会crash!