Swift 创建通用单例

Swift 创建通用单例,swift,generics,singleton,factory,Swift,Generics,Singleton,Factory,(对我来说)这有点令人头痛。基本上,我希望有两个不同的单例继承自同一个类。在这两种情况下,我都想使用一个自身派生的特定类。所以我有Utility和AUtil:Utility和BUtil:Utility。和Singleton,分别在胃和B中用作Singleton。我在所有领域都失败了。最后一次尝试是一个工厂模式,它只是将Swift 1.2改为SEGFULT: protocol Initializable { init() } class A:Initializable { var x = "A

(对我来说)这有点令人头痛。基本上,我希望有两个不同的单例继承自同一个类。在这两种情况下,我都想使用一个自身派生的特定类。所以我有
Utility
AUtil:Utility
BUtil:Utility
。和
Singleton
,分别在胃和
B
中用作
Singleton
。我在所有领域都失败了。最后一次尝试是一个工厂模式,它只是将Swift 1.2改为SEGFULT:

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
}

(我已经测试了上面的代码,并使其在Swift 1.2中运行。)

受findalls实现的启发,我构建了自己的单例生成器,它功能更强

您可以在Swift中创建任何类或结构类型的单例。您需要做的唯一一件事是根据您的类型实现两种不同协议中的一种,并使用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 { $0 } }

    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
    }
}
这可能看起来有点吓人,但不要害怕这段代码。协议扩展中的公共函数将为您创建两个访问点。 例如,您现在可以编写如下代码:

// 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 { $0 - 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 { $0 + 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 { $0; 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 { $0.name = "A"; return $0 }.name)
print(A.singleton.name) 
// should print "hello world" and twice the string "A"
如果您有任何想法如何增强此代码并使其更安全,请让我知道。我将很快在GitHub(MIT许可证)上发布这段代码,这样每个人都可以从中受益

更新:我对代码做了一点修改,这样您就可以在第一次调用setter函数时,通过setter函数传递一个自定义初始化的类实例


更新2:我删除了ClassInstance协议并修改了私有还原功能。
实例
协议现在称为
SingletonType
。setter函数不再是可选的现在,Xcode 7 beta 3将崩溃,并在调用getter时提供一个
非法指令:4
错误。但这是一个已确认的beta bug。

看起来很有希望。谢谢:-)我看看今天是否能用上。使用
flatMap
有什么原因吗<代码>如果让o=(实例[name]as?T)似乎也能工作。“我必须查找新方法,因为它是最新的1.2 Beta之一。”托马斯基利安:对不起,你说得对。我不知道,
if let
可以打开一个双重包装的选项值,
Initializable???
。谢谢另外,请注意我上面的代码不是线程安全的,导致多线程中没有显式同步的争用条件。由于单例是在初始化期间分配的,因此这对我来说不是问题:-)
setinstance
可能是您可能更正的错误:-)我在通用类上使用您的代码进行缓存管理。很好@代码有点过时了。如果您感兴趣,可以在GitHub上查看我的最终版本:很高兴我能帮助别人。
// 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 { $0 - 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 { $0 + 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 { $0; 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 { $0.name = "A"; return $0 }.name)
print(A.singleton.name) 
// should print "hello world" and twice the string "A"