使用DISPATCH_SOURCE_TYPE_DATA_ADD派发源

int main(int argc, const char * argv[]) {
    
    @autoreleasepool {
        NSLog(@"==========自定义ADD派发源===========");
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        //1、先创建派发源
        dispatch_source_t dispatchSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue);
        
        //2、设置事件响应体
        dispatch_source_set_event_handler(dispatchSource, ^{
           
            NSLog(@"%lu", dispatch_source_get_data(dispatchSource));
        });
        
        dispatch_source_set_registration_handler(dispatchSource, ^{
            NSLog(@"dispatch source is resumed");
        });
        //3、启动派发源
        dispatch_resume(dispatchSource);
        
        //触发自定义事件
        dispatch_async(queue, ^{
            for (int i = 0; i < 4; i++) {
                dispatch_source_merge_data(dispatchSource, 1);
                [NSThread sleepForTimeInterval:0.01];
            }
        });
     
        [[NSRunLoop currentRunLoop]runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5]];
        NSLog(@"------------------------");
        
        dispatch_source_set_cancel_handler(dispatchSource, ^{
            NSLog(@"dispatch source is canceled");
        });
        dispatch_source_cancel(dispatchSource);//注意:凡是被取消的派发源,以后都不能再次重新启动了;但是派发源仍在监听事件,但是不会将block派发到制定队列。
        
        //再次触发自定义事件
        dispatch_async(queue, ^{
            for (int i = 0; i < 4; i++) {
                dispatch_source_merge_data(dispatchSource, 1);
                [NSThread sleepForTimeInterval:0.01];
            }
        });
        
        [[NSRunLoop currentRunLoop]runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5]];
        NSLog(@"-----------------------");
    }
    
    return 0;
}
首先使用dispatch_source_create函数创建 dispatchsource,第1个参数表示它是一个自定义的_ADD类型的监听,具体作用后面说,2、3参数这里面没有作用设置为0即可,第4个参数 表示一旦事件触发就将要执行的代码块添加到主队列中执行,接着我们使用dispatch_source_set_event_handler函数为这个监 听设置事件的源和响应体,第1个参数表示这个监听是响应用户自定义事件的,也就是我们上面定义的dispatchsource,第2个参数是负责响应的代 码块。很有意思的是当我们创建监听后,这个监听默认是挂起的,需要手动恢复,所以我们使用dispatch_resume函数恢复这个监听,为了测试这个 监听,我们后面又通过for循环触发事件,触发事件的函数就是dispatch_source_merge_data,这个函数负责触发自定义事件,第1 个参数表示要触发哪个监听,第2个参数是向监听传入一个unsigned long 类型的值, 我们这里传入循环的索引,好了,整体来看这段程序,dispatch_source_merge_data函数会被执行4次,并分别传入0、1、2、3这 4个值,既然dispatch_source_merge_data负责触发事件,那么我们在监听里面的响应体应该会监听到,结果也确实监听到了,但是并 不是我们想象的那样打印4次,而是只打印了一次,打印结果是4次传入值相加的和,也就是6,这就是 DISPATCH_SOURCE_TYPE_DATA_ADD参数的作用,这个监听在创建之初就被设置为自定义监听,并且会把监听结果相加,然后统一响 应。这里你应该会奇怪,既然结果会相加并统一响应,那跟触发的时候加好,然后触发一次有什么区别呢,好吧,我们把触发事件的for循环改一下,然后再运 行,看看会发生什么
 
for(i = 0;i<4;i++){  
    dispatch_source_merge_data(source,i);  
    [NSThread sleepForTimeInterval:0.0001];  
}  
我们在触发事件的地方加上0.0001秒的延迟,然后运行整个程序多次,你会发现奇怪 的现象,我们同样是触发4次事件,但是响应的次数变成不确定了,可能是1次,也可能是2次,如果你将延迟时间设置长点,甚至设置为0点几秒就能让响应的次 数变为固定的4次,为什么会这样呢,其实这就是这个自定义事件设计的初衷。如果同一时间同一个事件被触发的频率非常密集,那么 dispatchsource会将这些密集的响应相加统计做出响应,但是如果触发的相对零散,那么dispatch source会分别进行响应,这其实是在智能的控制UI的没必要的更新操作,因为那些几乎在同一时间更新进度条的操作完全可以统一进行更新,没有必要每次 都更新一下。这样做也会减少UI线程的负担,例如更新进度条的同时,你的UI可能还在同时响应用户的输入、触碰等工作。当然你可以选择实时更新,办法就是 直接使用使用dispatch_async直接更新界面。Dispatch source在统一响应完毕后计数变为0,后面再触发的会重新相加。DISPATCH_SOURCE_TYPE_DATA_OR会将所有监听到的值逻辑与 操作,然后统一触发。貌似没DISPATCH_SOURCE_TYPE_DATA_ADD常用。













你可能感兴趣的:(object_c2.0,Mac,osX,ios)