Swift中dispatch_once的示例

时间:2015-07-05 22:47:14

标签: swift cocoa swift2

是否有一个如何在Swift中使用 dispatch_once 的示例? (最好是Apple的一个。)

注意:在这种情况下,我是not using it for a singleton;我想要一次运行任意代码。

更新:我主要对在实例方法中使用它时推荐的约定感兴趣,但在类方法,函数和全局上下文中的使用对于完整性是有用的。

3 个答案:

答案 0 :(得分:28)

dispatch_once_t是类型别名(Int)。标题文档:

/*!
 * @typedef dispatch_once_t
 *
 * @abstract
 * A predicate for use with dispatch_once(). It must be initialized to zero.
 * Note: static and global variables default to zero.
 */
typealias dispatch_once_t = Int

以下是dispatch_once文档的引用:

  

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

令牌变量必须存储在全局/静态范围内,并且必须初始化为零,这会产生以下代码:

import Foundation

var token: dispatch_once_t = 0
dispatch_once(&token) { () -> Void in
  print("Called once")
}

如果省略= 0token初始化),它就无法工作,因为编译器会产生错误变量'令牌的地址'在初始化之前采取,尽管静态和全局变量默认为零。在Xcode 7B2中测试。

基于评论的更多示例。如果你在class方法内,你有几种可能性。

您无法在方法内声明静态属性,否则编译器产生静态属性只能在类型错误上声明。这不起作用:

class func doItOnce() {
  static var token: dispatch_once_t = 0
  ...
}

必须在类型上声明。这是在Swift 1.2(Xcode 6.3 IIRC)中引入的。

  

现在允许在类中使用“静态”方法和属性(作为   “class final”的别名。您现在可以声明静态存储   类中的属性,具有全局存储并且是懒惰的   在第一次访问时初始化(如全局变量)。现在的协议   声明类型要求为“静态”要求而不是   宣称它们是“阶级”要求。 (17198298)

那么,如果我们不喜欢全局变量,我们可以做些什么呢?

类型上的静态变量

class MyClass {
  private static var token: dispatch_once_t = 0

  class func doItOnce() {
    dispatch_once(&token) {
      print("Do it once")
    }
  }
}

包含在struct

中的方法中的静态

不喜欢你们班级的静态财产吗?想在你的方法中拥有它吗?将它包装在这样的结构中:

class func doItOnce() {
  struct Tokens { static var token: dispatch_once_t = 0 }
  dispatch_once(&Tokens.token) {
    print("Do it once")
  }
}

实际上,我并不知道任何Apple建议,最佳做法,......如何为dispatch_once做到这一点。只需使用您最喜欢的任何一种,对您感觉良好并且只满足标准全局/静态范围。

答案 1 :(得分:4)

对于那些好奇的人,对我而言,这种方法对此有用:

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()
        }

    }
}

通过不声明静态var,它具有预期的行为。话虽如此,对于任何严肃的项目来说,这绝对不是推荐的,因为在Docs中(正如你的说法所说),它声明:

  

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

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

答案 2 :(得分:-1)

罗伯特沃塔的回答可能是最好的。因为我总是试图避免导入基金会并使用纯粹的' Swift解决方案(使用Swift3.0我可以改变我的观点),我想与你分享我自己的,非常简单的方法。我希望,这段代码是不言自明的

class C {
    private var i: Int?
    func foo()->Void {
        defer {
            i = 0
        }
        guard i == nil else { return }
        print("runs once")
    }
}

let c = C()
c.foo() // prints "runs once"
c.foo()
c.foo()

let c1 = C()
c1.foo() // prints "runs once"
c1.foo()

class D {
    static private var i: Int?
    func foo()->Void {
        defer {
            D.i = 0
        }
        guard D.i == nil else { return }
        print("runs once")
    }
}

let d = D()
d.foo() // prints "runs once"
d.foo()
let d2 = D()
d.foo()