2015-04-10 1 views
6

Questo è un po 'un banger capo (per me). Fondamentalmente voglio avere 2 diversi singleton che ereditano dalla stessa classe. In entrambi voglio usare una certa classe derivata da se stessa. Così ho Utility e sia AUtil:Utility e BUtil:Utility. E Singleton utilizzato come ASingleton utilizzando AUtility nello stomaco e B rispettivamente. Ho fallito su tutte le frontiere. L'ultimo tentativo è stato un modello di fabbrica, che semplicemente ha Swift 1.2 per segfault:Creazione di un generico singleton

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

Come detto ho anche provato a fare il seguente schema generico:

private let _SingletonSharedInstance = StaticClass() 

class StaticClass { 
    class var sharedInstance : StaticClass { 
    return _SingletonSharedInstance 
    } 
} 

let s = StaticClass.sharedInstance 

(Questo non è generico, come si Vedi. Ma tutti i miei tentativi fallirono e così mostro il mio punto di partenza.)

In ogni caso, mi sembra di essere perso tra morte e rovina.

risposta

4

Intendi qualcosa del genere?

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 lato di utilizzo, ad esempio.

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) 

(ho testato il codice precedente e preso a lavorare a Swift 1.2.)

+0

Sembra promettente. Grazie :-) Vedrò se riesco a farlo funzionare oggi. –

+0

C'è un motivo per usare 'flatMap'? 'Se let o = (istanze [nome] come? T)' sembra funzionare altrettanto bene. Ho dovuto cercare quel nuovo metodo poiché è nuovo con una delle ultime 1.2 beta. –

+0

@ThomasKilian Scusa, hai ragione.Non sapevo che il 'if let' poteva scartare un valore di opzione doppiamente incartato,' Inizializzabile '. Grazie! – findall

3

Ispirato implementazione findalls, ho costruire il mio generatore di Singleton, che è un po 'più potente.

È possibile creare un singleton di qualsiasi tipo di classe o struttura in Swift. L'unica cosa che devi fare è implementare uno dei due diversi protocolli per il tuo tipo e usare Swift 2.0 o più recente.

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

Questo può sembrare un po 'spaventoso, ma non abbiate paura di questo codice. La funzione pubblica all'interno dell'estensione del protocollo creerà per te due punti di accesso. Per esempio si sarà in grado di scrivere codice in questo modo la società:

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

Se avete qualche idea di come migliorare questo codice e renderlo ancora più sicuro, per favore fatemelo sapere. Spingerò presto questo codice su GitHub (licenza MIT), in modo che tutti possano trarne vantaggio.

UPDATE: Ho modificato leggermente il codice in modo da poter passare un'istanza inizializzata personalizzata di una classe con la funzione setter quando è chiamata la prima volta.

UPDATE 2: Ho rimosso il protocollo ClassInstance e ho modificato la funzione di ripristino privato. Il protocollo Instance viene ora chiamato SingletonType. La funzione setter non è più opzionale. Al momento Xcode 7 beta 3 si blocca e fornisce un erroreillegal instruction: 4quando si chiama il getter. Ma questo è un bug beta confermato.

+1

'setInstnace' è probabilmente un refuso che potresti correggere :-) –

+0

Uso il tuo codice su una classe generica per la gestione della cache. Funziona alla grande ! –

+0

@CanATAC il codice è un po 'obsoleto. Se sei interessato puoi controllare la mia versione finale su GitHub: https://github.com/DevAndArtist/SingletonGenerator Contento di poter aiutare qualcuno. – DevAndArtist