需求:延后一段时间再执行

本文详细探讨了GCD中dispatch_after的实现机制,通过源码分析指出其并不立即执行,而是将任务提交到队列中等待指定时间后执行。对比NSTimer和NSObject的延迟执行方式,dispatch_after不依赖于runloop,更适用于后台任务。同时,文章指出了dispatch_after的不可取消性以及其时间精度的调整策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有三种方案

001 NSTimer 需要依赖于指定runloop的运行模式

002 NSObject.performSelector:withObject:afterDelay: 依赖runloop

003 dispatch_after 不依赖Runloop

- (void)testDispatchAfter{

    NSLog(@"start----%s----",__func__);

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        NSLog(@"3秒----");

    });

}

2020-10-29 20:56:59.818162+0800 GCDPropertyQueue[1828:86866] start-----[ViewController testDispatchAfter]----

2020-10-29 20:57:02.818514+0800 GCDPropertyQueue[1828:86866] 3秒----

还是看源码

static inline void

_dispatch_after(dispatch_time_t when, dispatch_queue_t dq,

void *ctxt, void *handler, bool block)

{

dispatch_timer_source_refs_t dt;

dispatch_source_t ds;

uint64_t leeway, delta;

 

if (when == DISPATCH_TIME_FOREVER) {

#if DISPATCH_DEBUG

DISPATCH_CLIENT_CRASH(0, "dispatch_after called with 'when' == infinity");

#endif

return;

}

//获取到时间

delta = _dispatch_timeout(when);

 

if (delta == 0) { //如果为零那么开启异步线程立马执行

if (block) {

return dispatch_async(dq, handler);

}

return dispatch_async_f(dq, ctxt, handler);

}

 

leeway = delta / 10; // <rdar://problem/13447496>

//NSEC_PER_MSEC 一毫秒

if (leeway < NSEC_PER_MSEC) leeway = NSEC_PER_MSEC;

if (leeway > 60 * NSEC_PER_SEC) leeway = 60 * NSEC_PER_SEC;

 

// this function can and should be optimized to not use a dispatch source

//创建一个调度资源

ds = dispatch_source_create(&_dispatch_source_type_after, 0, 0, dq);

dt = ds->ds_timer_refs;

//分配一个持续调度对象

dispatch_continuation_t dc = _dispatch_continuation_alloc();

if (block) {

_dispatch_continuation_init(dc, dq, handler, 0, 0);

} else {

_dispatch_continuation_init_f(dc, dq, ctxt, handler, 0, 0);

}

// reference `ds` so that it doesn't show up as a leak

dc->dc_data = ds;

_dispatch_trace_item_push(dq, dc);

os_atomic_store2o(dt, ds_handler[DS_EVENT_HANDLER], dc, relaxed);

 

dispatch_clock_t clock;

uint64_t target;

//调度时间给时钟以及target

_dispatch_time_to_clock_and_value(when, &clock, &target);

//判断是否是调度时针墙

if (clock != DISPATCH_CLOCK_WALL) {

//调整精度

leeway = _dispatch_time_nano2mach(leeway);

}

//du_timer_flags 异或从clock异步时间

// 执行target

//执行时间间隔以及截止时间

//保持活跃度

dt->du_timer_flags |= _dispatch_timer_flags_from_clock(clock);

dt->dt_timer.target = target;

dt->dt_timer.interval = UINT64_MAX;

dt->dt_timer.deadline = target + leeway;

dispatch_activate(ds);

}

void

dispatch_after(dispatch_time_t when, dispatch_queue_t queue,

dispatch_block_t work)

{

_dispatch_after(when, queue, NULL, work, true);

}

dispatch_after 并不是在指定时间后执行,而是在指定时间之后才将任务提交到队列中

_dispatch_trace_item_push(dq, dc);

os_atomic_store2o(dt, ds_handler[DS_EVENT_HANDLER], dc, relaxed);

dispatch_after在延后执行的block中无法直接取消

dt->du_timer_flags |= _dispatch_timer_flags_from_clock(clock);

dt->dt_timer.target = target;

dt->dt_timer.interval = UINT64_MAX;

dt->dt_timer.deadline = target + leeway;

dispatch_activate(ds);

判断when是否是现在,异步执行它,否则创建一个dispatch source 以便在指定时间触发异步执行

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值