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唤醒了...