launch once 与 dispatch once

昨天发了个 launch once 的 code snippet 


陆续有朋友和我讨论,今天详细解释下。

launch once 这段代码实现了在一个 Engine 对象生命周期内只能调用一次 launch 方法:




而我们常用的 dispatch once 由于其使用了一个 static 变量作为 onceToken,所以会在 App 生命周期内只调用一次:




所以是这样的效果:




并不是我们所期望的。

有朋友考虑这个写法是否线程安全,其实当使用一个标记 property 的传统写法来干同样的事时,真的有考虑过线程安全么?不过也去查看了下 runtime 源码,对 association 的访问和操作都是通过内部一个 AssociationsManager C++ 类实现,而在它的实例的生命周期内,存在一把 spinlock 来保证线程安全:




因此反而还挺线程安全。昨天还讨论了有没有可能利用 dispatch_once 加上一个非 static 变量的 onceToken 来实现这个需求,比如用 self 当 onceToken。后经研究发现并不能做到,因为 dispatch_once 的实现对 onceToken 有比较苛刻的限制条件:

  • onceToken 初始值必须是 0

  • onceToken 必须是 long 类型

  • 在生命周期内 onceToken 的地址不能修改,且值不能被乱改


任何不满足都会 BAD_ACCESS,所以用 self 当 onceToken 是不可行的,只可能用一个成员变量来充当,但是这已经违背了“不添加成员变量”的初衷,晚上失眠时想了好久怎么能找到个酷炫的 onceToken 来解决这个难题,结果失眠的时间更久了...


有关 dispatch_once 内部的精巧设计,可以拜读梦维的系列博文,讲的非常之深入:


http://www.dreamingwish.com/article/gcd-guide-dispatch-once-1.html


最后,还有吐槽为啥那段代码就不多打几个回车的,其实只是为了臭美用两行代码就能搞定 - -,平时用该咋写咋写啊

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值