是否有一个如何在Swift中使用 dispatch_once 的示例? (最好是Apple的一个。)
注意:在这种情况下,我是not using it for a singleton;我想要一次运行任意代码。
更新:我主要对在实例方法中使用它时推荐的约定感兴趣,但在类方法,函数和全局上下文中的使用对于完整性是有用的。
答案 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")
}
如果省略= 0
(token
初始化),它就无法工作,因为编译器会产生错误变量'令牌的地址'在初始化之前采取,尽管静态和全局变量默认为零。在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)
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()