Cocoa dispatch_once 每个实例

Posted

技术标签:

【中文标题】Cocoa dispatch_once 每个实例【英文标题】:Cocoa dispatch_once per instance 【发布时间】:2014-08-08 10:29:11 【问题描述】:

如何使用dispatch_once,,以便给定代码在每个实例生命周期内执行一次。

相当于在对象内部拥有一个属性,并像这样使用它:

- (void)viewWillAppear:(..).. 

   // ...

   if (self.isDispatched == NO) 
      // ...
      self.isDispatched = YES;
   


但我不想使用额外的属性,而是 dispatch_once_t 或类似的。

【问题讨论】:

为什么不能在init方法或viewDidLoad方法中运行代码? 因为它需要在 viewWillAppear 运行 :) 无论您使用标志还是dispatch_once_t,它都必须是实例变量(这与属性不同)。而且,是的,您可以使用 dispatch_once_t 作为实例变量,尽管经常有相反的说法。 你能发布一些代码作为答案吗? 你为什么还要使用dispatch_once呢?它对于处理线程安全很有用,但viewWillAppear 方法将始终在主线程上调用。根据 KISS 原则,我认为在这种情况下 BOOL 属性已经足够好了。或者你可以在某些情况下使用延迟初始化的属性(这取决于你想在viewWillAppear中做什么)。 【参考方案1】:

无法满足您的要求。 dispatch_once 只能用于以前从未写入过的内存,并且您无法通过实例变量来保证这一点。 Greg Parker says so,他会知道的。

改为使用问题中的代码,但将其包装在 @synchronized 块中。

如果您真的想避免添加实例变量,您可以使用单独的单例来管理可变集。您必须向它注册实例并在解除分配时将其删除。确保这个助手类只保存弱引用;见NSMapTableNSMapTableWeakMemory

【讨论】:

【参考方案2】:

对于那些好奇并作为额外提示的人,对我来说,这种方法对此很有用:

class SomeVC : UIViewController 
    private var token: dispatch_once_t = 0

    public override func viewDidAppear(animated: Bool) 
        super.viewDidAppear(animated)

        dispatch_once(&token)  () -> Void in
            self.doSomethingOnce()
        

    

通过不声明静态变量,它具有预期的行为。话虽如此,这绝对不推荐用于任何严肃的项目,因为在文档中(正如您所说的那样)它指出:

谓词必须指向存储在全局或静态范围内的变量。使用带有自动或动态存储(包括 Objective-C 实例变量)的谓词的结果是未定义的。

如果我们不想在未来遇到任何奇怪的错误和未定义的行为,我会坚持 Apple 所说的。但是玩这些东西还是不错的,不是吗? =)

【讨论】:

+一个用于注意“谓词必须指向存储在全局或静态范围内的变量。”

以上是关于Cocoa dispatch_once 每个实例的主要内容,如果未能解决你的问题,请参考以下文章

为啥苹果推荐使用 dispatch_once 来实现 ARC 下的单例模式?

Cocoa 中的共享对象

带有选项卡式导航的 Cocoa-Touch 后退按钮

Cocoa:NIB 文件创建的实例的 var 名称是啥?

Cocoa:从另一个类触发 NSWindow makeKeyAndOrderFront 实例方法

cocoa -[Person copyWithZone:]: 无法识别的选择器发送到实例