Apple Silicon设备上dispatch_time计算异常问题求助
dispatch_time 在Apple Silicon及iOS设备上的计算异常问题
我有一段在Intel Mac上可正常运行的Objective-C代码,但在搭载M1芯片的Mac设备上运行失败。代码如下:
dispatch_time_t now = dispatch_time(DISPATCH_TIME_NOW, 0); dispatch_time_t delta = (uint64_t)(1 * NSEC_PER_SEC); dispatch_time_t when = dispatch_time(now, delta); NSLog(@"now: %llu", now); NSLog(@"delta: %llu", delta); NSLog(@"when: %llu", when); NSLog(@"real delta: %llu", when-now);
运行后输出示例如下:
now: 1272914827933 delta: 1000000000 when: 1272938827933 real delta: 24000000
按照计算,1272914827933 + 1000000000 应等于1273914827933,而非1272938827933。为何该问题仅在部分Mac设备上出现?
补充说明:此问题在真实iPhone设备上同样存在。只需创建一个新的Objective-C Xcode项目,将代码粘贴到AppDelegate中并在手机上运行即可复现。
问题原因
你错误理解了dispatch_time函数的参数用法。第二个参数不是直接的纳秒偏移量,而是一个带符号的偏移值,且dispatch_time_t的底层存储格式在不同架构上有差异:
- 在Intel(x86_64)架构上,
dispatch_time_t直接存储纳秒时间戳,所以你的代码碰巧能得到预期结果; - 在Apple Silicon(arm64)架构以及iOS设备上,
dispatch_time_t是一个复合结构:高几位标记时间类型(比如相对时间/绝对时间),低几位存储偏移值,直接用数值相加或相减完全不符合其设计逻辑。
正确的用法是,dispatch_time的第二个参数应该是相对于第一个参数的带符号偏移,如果要基于当前时间创建延迟,正确的写法是:
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);
而不是先获取now再传入。另外,如果你需要计算时间差,应该使用dispatch_time的配套逻辑,或者将dispatch_time_t转换为绝对时间戳后再计算:
uint64_t nowAbs = dispatch_walltime(NULL, 0); uint64_t whenAbs = dispatch_walltime(NULL, 1 * NSEC_PER_SEC); NSLog(@"real delta: %llu", whenAbs - nowAbs);
总结
dispatch_time_t不是简单的64位纳秒数值,其内部格式依赖架构,不能直接做算术运算;- 不要将
dispatch_time的返回值作为第一个参数再次传入该函数,这属于错误用法; - 跨架构的时间处理,应该使用
dispatch_walltime来获取统一的绝对时间戳,或者使用NSDate等高层API。
内容的提问来源于stack exchange,提问作者Kevin Renskers
相关产品推荐
相关产品推荐

