创建通用单例
Creating a generic singleton
这有点让人头疼(对我来说)。基本上我想要 2 个不同的单例,它们继承自同一个 class。在任何一种情况下,我都想使用本身派生的某个 class 。所以我有 Utility
以及 AUtil:Utility
和 BUtil:Utility
。并且Singleton
被用作ASingleton
,分别在其胃中使用AUtility
和B
。我在所有领域都失败了。最后一次尝试是工厂模式,它只是将 Swift 1.2 变为 Segfault:
protocol Initializable { init() }
class A:Initializable {
var x = "A"
required init() {}
}
class B:Initializable {
var x = "B"
required init() {}
}
class C {
let t:Initializable
init(t:Initializable) {
self.t = t
println(t)
}
func factory() {
println(t.dynamicType())
}
}
如前所述,我还尝试使以下模式通用:
private let _SingletonSharedInstance = StaticClass()
class StaticClass {
class var sharedInstance : StaticClass {
return _SingletonSharedInstance
}
}
let s = StaticClass.sharedInstance
(如您所见,这不是通用的。但是我所有的尝试都失败了,所以我展示了我的起点。)
反正我好像在生死之间迷失了方向
你的意思是这样的吗?
protocol Initializable: class { init() }
private var instances = [String: Initializable]()
func singletonInstance<T: Initializable>(_ ty: T.Type = T.self) -> T {
let name = NSStringFromClass(ty)
if let o = (instances[name] as? T) {
return o
}
let o = ty()
instances[name] = o
return o
}
它的使用方面,例如。
class Foo: Initializable { required init() {} }
class Bar: Initializable { required init() {} }
let foo1 = singletonInstance() as Foo // or `singletonInstance(Foo.self)`
let foo2 = singletonInstance() as Foo
assert(foo1 === foo2)
let bar1 = singletonInstance() as Bar
let bar2 = singletonInstance() as Bar
assert(bar1 === bar2)
(我已经测试了上面的代码并让它在 Swift 1.2 中工作。)
受findalls实现的启发,自己搭建了一个单例生成器,功能稍微强大一些。
您可以在 Swift 中创建任何 Class 或结构类型的单例。您唯一需要做的就是为您的类型实现两种不同协议中的一种,并使用 Swift 2.0 或更新版本。
public protocol SingletonType { init() }
private var singletonInstances = [String: SingletonType]()
extension SingletonType {
// this will crash Xcode atm. it's a Swift 2.0 beta bug. Bug-ID: 21850697
public static var singleton: Self { return singleton { [=10=] } }
public static func singleton(setter: (_: Self) -> Self) -> Self {
guard let instance = singletonInstances["\(self)"] as? Self else {
return setInstance(self.init(), withSetter: setter, overridable: true)
}
return setInstance(instance, withSetter: setter, overridable: false)
}
private static func setInstance(var instance: Self, withSetter setter: (_: Self) -> Self, overridable: Bool) -> Self {
instance = restoreInstanceIfNeeded(instance1: instance, instance2: setter(instance), overridable: overridable)
singletonInstances["\(self)"] = instance
return instance
}
private static func restoreInstanceIfNeeded(instance1 i1: Self, instance2 i2: Self, overridable: Bool) -> Self {
// will work if the bug in Swift 2.0 beta is fixed !!! Bug-ID: 21850627
guard i1.dynamicType is AnyClass else { return i2 }
return ((i1 as! AnyObject) !== (i2 as! AnyObject)) && !overridable ? i1 : i2
}
}
这可能看起来有点可怕,但不要害怕这段代码。协议扩展中的 public 函数将为您创建两个访问点。
例如,您现在可以编写如下代码:
// extend your type: as an example I will extend 'Int' here
extension Int : SingletonType {} // nothing else to do, because Int already has an 'init()' initializer by default
// let the magic happen
Int.singleton // this will generate a singleton Int with 0 as default value
Int.singleton { (_) -> Int in 100 } // should set your Int singleton to 100
Int.singleton { [=11=] - 55 } // your singleton should be 45 now
// I need to mention that Xcode will produce the setter like this and trow an error
Int.singleton { (yourCustomInstanceName) -> Self in // replace 'Self' with 'Int' and you should be fine
return yourCustomInstanceName
}
// btw. we just ignored the return value everywhere
print(Int.singleton) // will print 45 here
var singleton2 = Int.singleton { [=11=] + 5 }
singleton2 += 10
print(Int.singleton) // should print 50, because 'singleton2' is just a copy of an Int value type
class A : SingletonType {
var name = "no name"
required init() {}
}
A.singleton { [=11=]; let i = A(); i.name = "hello world"; return i } // custom init on first singleton call for type A
print(A.singleton.name)
print(A.singleton { [=11=].name = "A"; return [=11=] }.name)
print(A.singleton.name)
// should print "hello world" and twice the string "A"
如果您对如何增强此代码并使其更安全有任何想法,请告诉我。我会尽快将这段代码推送到GitHub(MIT License),让大家从中受益。
更新: 我稍微修改了代码,因此您现在可以在调用 setter 函数时传递 class 的自定义初始化实例第一次。
更新 2: 我删除了 Class 实例协议并修改了私有恢复功能。 Instance
协议现在称为 SingletonType
。 setter 函数不再是可选的。 现在 Xcode 7 beta 3 将崩溃并在您调用 getter.[=31 时提供 illegal instruction: 4
错误=] 但这是一个已确认的测试版错误。
这有点让人头疼(对我来说)。基本上我想要 2 个不同的单例,它们继承自同一个 class。在任何一种情况下,我都想使用本身派生的某个 class 。所以我有 Utility
以及 AUtil:Utility
和 BUtil:Utility
。并且Singleton
被用作ASingleton
,分别在其胃中使用AUtility
和B
。我在所有领域都失败了。最后一次尝试是工厂模式,它只是将 Swift 1.2 变为 Segfault:
protocol Initializable { init() }
class A:Initializable {
var x = "A"
required init() {}
}
class B:Initializable {
var x = "B"
required init() {}
}
class C {
let t:Initializable
init(t:Initializable) {
self.t = t
println(t)
}
func factory() {
println(t.dynamicType())
}
}
如前所述,我还尝试使以下模式通用:
private let _SingletonSharedInstance = StaticClass()
class StaticClass {
class var sharedInstance : StaticClass {
return _SingletonSharedInstance
}
}
let s = StaticClass.sharedInstance
(如您所见,这不是通用的。但是我所有的尝试都失败了,所以我展示了我的起点。)
反正我好像在生死之间迷失了方向
你的意思是这样的吗?
protocol Initializable: class { init() }
private var instances = [String: Initializable]()
func singletonInstance<T: Initializable>(_ ty: T.Type = T.self) -> T {
let name = NSStringFromClass(ty)
if let o = (instances[name] as? T) {
return o
}
let o = ty()
instances[name] = o
return o
}
它的使用方面,例如。
class Foo: Initializable { required init() {} }
class Bar: Initializable { required init() {} }
let foo1 = singletonInstance() as Foo // or `singletonInstance(Foo.self)`
let foo2 = singletonInstance() as Foo
assert(foo1 === foo2)
let bar1 = singletonInstance() as Bar
let bar2 = singletonInstance() as Bar
assert(bar1 === bar2)
(我已经测试了上面的代码并让它在 Swift 1.2 中工作。)
受findalls实现的启发,自己搭建了一个单例生成器,功能稍微强大一些。
您可以在 Swift 中创建任何 Class 或结构类型的单例。您唯一需要做的就是为您的类型实现两种不同协议中的一种,并使用 Swift 2.0 或更新版本。
public protocol SingletonType { init() }
private var singletonInstances = [String: SingletonType]()
extension SingletonType {
// this will crash Xcode atm. it's a Swift 2.0 beta bug. Bug-ID: 21850697
public static var singleton: Self { return singleton { [=10=] } }
public static func singleton(setter: (_: Self) -> Self) -> Self {
guard let instance = singletonInstances["\(self)"] as? Self else {
return setInstance(self.init(), withSetter: setter, overridable: true)
}
return setInstance(instance, withSetter: setter, overridable: false)
}
private static func setInstance(var instance: Self, withSetter setter: (_: Self) -> Self, overridable: Bool) -> Self {
instance = restoreInstanceIfNeeded(instance1: instance, instance2: setter(instance), overridable: overridable)
singletonInstances["\(self)"] = instance
return instance
}
private static func restoreInstanceIfNeeded(instance1 i1: Self, instance2 i2: Self, overridable: Bool) -> Self {
// will work if the bug in Swift 2.0 beta is fixed !!! Bug-ID: 21850627
guard i1.dynamicType is AnyClass else { return i2 }
return ((i1 as! AnyObject) !== (i2 as! AnyObject)) && !overridable ? i1 : i2
}
}
这可能看起来有点可怕,但不要害怕这段代码。协议扩展中的 public 函数将为您创建两个访问点。 例如,您现在可以编写如下代码:
// extend your type: as an example I will extend 'Int' here
extension Int : SingletonType {} // nothing else to do, because Int already has an 'init()' initializer by default
// let the magic happen
Int.singleton // this will generate a singleton Int with 0 as default value
Int.singleton { (_) -> Int in 100 } // should set your Int singleton to 100
Int.singleton { [=11=] - 55 } // your singleton should be 45 now
// I need to mention that Xcode will produce the setter like this and trow an error
Int.singleton { (yourCustomInstanceName) -> Self in // replace 'Self' with 'Int' and you should be fine
return yourCustomInstanceName
}
// btw. we just ignored the return value everywhere
print(Int.singleton) // will print 45 here
var singleton2 = Int.singleton { [=11=] + 5 }
singleton2 += 10
print(Int.singleton) // should print 50, because 'singleton2' is just a copy of an Int value type
class A : SingletonType {
var name = "no name"
required init() {}
}
A.singleton { [=11=]; let i = A(); i.name = "hello world"; return i } // custom init on first singleton call for type A
print(A.singleton.name)
print(A.singleton { [=11=].name = "A"; return [=11=] }.name)
print(A.singleton.name)
// should print "hello world" and twice the string "A"
如果您对如何增强此代码并使其更安全有任何想法,请告诉我。我会尽快将这段代码推送到GitHub(MIT License),让大家从中受益。
更新: 我稍微修改了代码,因此您现在可以在调用 setter 函数时传递 class 的自定义初始化实例第一次。
更新 2: 我删除了 Class 实例协议并修改了私有恢复功能。 Instance
协议现在称为 SingletonType
。 setter 函数不再是可选的。 现在 Xcode 7 beta 3 将崩溃并在您调用 getter.[=31 时提供 illegal instruction: 4
错误=] 但这是一个已确认的测试版错误。