【发布时间】:2014-07-24 08:13:28
【问题描述】:
我正在尝试制定一个适合在 Swift 中使用的单例模型。到目前为止,我已经能够获得一个非线程安全模型:
class var sharedInstance: TPScopeManager {
get {
struct Static {
static var instance: TPScopeManager? = nil
}
if !Static.instance {
Static.instance = TPScopeManager()
}
return Static.instance!
}
}
将单例实例包装在静态结构中应该允许单个实例不与单例实例冲突而无需复杂的命名方案,并且应该使事情变得相当私密。显然,这个模型不是线程安全的。所以我尝试将dispatch_once 添加到整个内容中:
class var sharedInstance: TPScopeManager {
get {
struct Static {
static var instance: TPScopeManager? = nil
static var token: dispatch_once_t = 0
}
dispatch_once(Static.token) { Static.instance = TPScopeManager() }
return Static.instance!
}
}
但我在dispatch_once 行收到编译器错误:
无法将表达式的类型“Void”转换为类型“()”
我尝试了几种不同的语法变体,但它们似乎都有相同的结果:
dispatch_once(Static.token, { Static.instance = TPScopeManager() })
dispatch_once 使用 Swift 的正确用法是什么?我最初认为问题在于由于错误消息中的() 而导致的块问题,但我越看它,我越认为这可能是正确定义dispatch_once_t 的问题。
【问题讨论】:
-
我会删除所有静态代码并使用带有@lazy 初始化程序的只读属性。
-
这就是我的意思。不幸的是,我们仍然没有足够的内部信息。但是,恕我直言,
@lazy的任何实现都应该是线程安全的。 -
而且这种方式还有一个好处是不会将实现暴露给调用者的掠夺者。
-
您似乎也不能拥有@lazy 类变量。
-
小心!这种方法需要注意两点。首先,任何继承自它的类都必须覆盖 sharedInstance 属性。
Static.instance = TPScopeManager()强制实例类型。如果您使用Static.instance = self()之类的东西和所需的初始化程序,则会生成适当的类型类。即便如此,这是需要注意的重要一点,对于层次结构中的所有实例仅一次!要初始化的第一个类型是为所有实例设置的类型。我不认为 Objective-c 的行为是一样的。