singletons example swift generics singleton factory

swift - example - Creando un singleton genérico



singleton swift 3 (2)

Esto es un poco loco (para mí). Básicamente quiero tener 2 singleton diferentes que hereden de la misma clase. En cualquiera de los dos quiero usar una cierta clase que se deriva. Entonces tengo Utility y ambos AUtil:Utility y BUtil:Utility . Y Singleton que se usa como ASingleton usando AUtility en su estómago y B respectivamente. Fallé en todas las fronteras. El último intento fue un patrón de fábrica que simplemente convirtió Swift 1.2 en 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()) } }

Como dije, también intenté hacer el siguiente patrón genérico:

private let _SingletonSharedInstance = StaticClass() class StaticClass { class var sharedInstance : StaticClass { return _SingletonSharedInstance } } let s = StaticClass.sharedInstance

(Este no es genérico como ves, pero todos mis intentos fallaron y entonces muestro mi punto de partida).

De todos modos, parece que estoy perdido entre el destino y la muerte.


¿Te refieres a algo como esto?

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 }

Un lado de uso del mismo, por ejemplo.

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)

(He probado el código anterior y lo he puesto a funcionar en Swift 1.2.)


Inspirado por la implementación de findalls, construyo mi propio generador singleton, que es un poco más potente.

Puede crear un singleton de cualquier clase o tipo de estructura en Swift. Lo único que debe hacer es implementar uno de dos protocolos diferentes para su tipo y usar Swift 2.0 o posterior.

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

Esto puede parecer un poco aterrador, pero no tenga miedo de este código. La función pública dentro de la extensión de protocolo creará dos puntos de acceso para usted. Por ejemplo, ahora podrá escribir código como este:

// 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"

Si tiene alguna idea de cómo mejorar este código y hacerlo aún más seguro, hágamelo saber. Presionaré este código en GitHub (Licencia MIT) pronto, para que todos puedan beneficiarse de él.

ACTUALIZACIÓN: modifiqué un poco el código para que ahora pueda pasar una instancia inicializada personalizada de una clase con la función setter cuando se la llama por primera vez.

ACTUALIZACIÓN 2: eliminé el protocolo ClassInstance y modifiqué la función de restauración privada. El protocolo de Instance ahora se llama SingletonType . La función setter ya no es opcional. En este momento Xcode 7 beta 3 se bloqueará y proporcionará una illegal instruction: 4 error cuando llame al getter. Pero este es un error beta confirmado.