dispatch source的简单应用

作者: 无边小猪 | 来源:发表于2016-09-02 18:04 被阅读77次

dispatch source 到底做什么的,多说无益,上一小段代码一看便知。

- (void)fun_dispatch_source
{
   //创建一个在全局队列上执行的source
    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0,                             
                                                               dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
  //创建source执行的block
    dispatch_source_set_event_handler(source, ^{
        NSLog(@"do something");
    });
   //恢复执行
    dispatch_resume(source);
    void (^blocktemp)() = ^(){
   //发送消息给source,source收到后会执行定义好的block
        dispatch_source_merge_data(source, 1);
    };
   //起一个调用block的定时器
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(runBlock:)userInfo:blocktemp repeats:YES];
  //执行定时器
    [timer fire];
}
- (void)runBlock:(NSTimer *)timer
{
    if (timer.userInfo) {
        void(^block)(void) = timer.userInfo;
       //调用block
        block();
    }
}

在看另一段代码:

- (void)fun_timer
{
    NSTimeInterval period = 1.0; //设置时间间隔
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), period * NSEC_PER_SEC, 0); //每秒执行
    dispatch_source_set_event_handler(_timer, ^{
        NSLog(@"do something");
    });
    dispatch_resume(_timer);
}

两段代码输出一致:
结果:
2016-07-26 16:38:02.472 runloop[32866:223763] do something
2016-07-26 16:38:03.472 runloop[32866:223763] do something
2016-07-26 16:38:04.473 runloop[32866:223763] do something
2016-07-26 16:38:05.472 runloop[32866:223763] do something
......
后一段代码有点特殊需要注意的地方:_timer必须不能是局部变量,如果是本地变量代码段执行完毕后就会退出,自然也不会有输出了。

看了代码dispatch source的作用应该可以理解了:
dispatch source可以用于多线程之间的通信。
可以自己实现一个异步的kvo。
可以辅助block实现异步回调(block回调使用调用线程)。
可以用来实现倒计时
上述实现可以被其他形式替代但使用dispatch source相对更好管理。
runloop底层实现大量调用了dispatch source。
例如:

    dispatch_source_t timeout_timer = NULL;
    struct __timeout_context *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context));
    if (seconds <= 0.0) { // instant timeout
        seconds = 0.0;
        timeout_context->termTSR = 0ULL;
    } else if (seconds <= TIMER_INTERVAL_LIMIT) {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, DISPATCH_QUEUE_OVERCOMMIT);
        timeout_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        dispatch_retain(timeout_timer);
        timeout_context->ds = timeout_timer;
        timeout_context->rl = (CFRunLoopRef)CFRetain(rl);
        timeout_context->termTSR = startTSR + __CFTimeIntervalToTSR(seconds);
        dispatch_set_context(timeout_timer, timeout_context); // source gets ownership of context
        dispatch_source_set_event_handler_f(timeout_timer, __CFRunLoopTimeout);
        dispatch_source_set_cancel_handler_f(timeout_timer, __CFRunLoopTimeoutCancel);
        uint64_t ns_at = (uint64_t)((__CFTSRToTimeInterval(startTSR) + seconds) * 1000000000ULL);
        dispatch_source_set_timer(timeout_timer, dispatch_time(1, ns_at), DISPATCH_TIME_FOREVER, 1000ULL);
        dispatch_resume(timeout_timer);
    } else { // infinite timeout
        seconds = 9999999999.0;
        timeout_context->termTSR = UINT64_MAX;
    }
__CFRunLoopTimeout长这个样子:
static void __CFRunLoopTimeout(void *arg) {
    struct __timeout_context *context = (struct __timeout_context *)arg;
    context->termTSR = 0ULL;
    CFRUNLOOP_WAKEUP_FOR_TIMEOUT();
    CFRunLoopWakeUp(context->rl);
    // The interval is DISPATCH_TIME_FOREVER, so this won't fire again
}

简单来说就是把runloop唤醒了...

相关文章

网友评论

    本文标题:dispatch source的简单应用

    本文链接:https://www.haomeiwen.com/subject/jnqkettx.html