2016-08-09 1 views
3

Ich möchte eine Zuordnung von Protokollen zu Objekten erstellen, die diese Protokolle implementieren. Dann möchte ich eine Implementierung für ein bestimmtes Protokoll bekommen können. DieseWie gebe ich einen Wert aus einer generischen Funktion als Implementierung eines Protokolls zurück?

ist das, was ich bisher habe:

class Services { 
    var map = NSMapTable(keyOptions: .CopyIn, valueOptions: .WeakMemory) 

    func register<T>(type: T, target: AnyObject) { 
    map.setObject(target, forKey: String(type)) 
    } 

    func get<T>(type: T) -> AnyObject { 
    guard let target = map.objectForKey(String(type)) else { 
     fatalError("Not registered") 
    } 
    return target 
    } 
} 

Und ich kann es so nennen:

protocol Foo { 
    func qux() 
} 

class Bar: Foo { 
    func qux() {} 
} 

services.register(Foo.self, target: Bar()) 

Und das ist großartig. Aber wenn ich will, um es abzurufen:

let foo: Foo = services.get(Foo.self) 

... die obige Zeile erzeugt einen Fehler:

Foo.swift:12:34: Cannot convert call result type 'AnyObject' to expected type 'Foo'

Wie kann ich die generische Funktion angeben get ein Objekt zurückgibt, die das Protokoll in T verwiesen implementiert ?

Ich möchte vermeiden, bei dem Anruf zu müssen.

Antwort

0

Ich bin mir bewusst, dass Sie die gesenkten vermeiden wollen, aber ich denke, Sie sollten verwenden:

if let foo: Foo = services.get(Foo.self) as? Foo { 

} 

in Ihrem Fall, da ein protocol Foo: class funktioniert nicht.

0

Was get Rückkehr der gattungsgemäßen Art zu machen, Sie haben nicht einmal einen Typ-Parameter benötigen, weil Sie bereits haben:

func get<T>() -> T { 
    guard let target = map.objectForKey(String(T.self)) else { 
     fatalError("Not registered") 
    } 
    return target as! T // or you could make the return type an Optional if you want to allow getting a service that wasn't registered. 
} 

Dann können Sie es wie folgt verwenden:

let foo: Foo = services.get() 
1

Ich bin mir nicht sicher, ob dies für Ihren Zweck geeignet ist, aber Sie können etwas wie dieses schreiben:

class Services { 
    var map = NSMapTable(keyOptions: .CopyIn, valueOptions: .WeakMemory) 

    func register<T>(type: T.Type, target: T) { 
     guard let object = target as? AnyObject else { 
      fatalError("Cannot register") 
     } 
     map.setObject(object, forKey: String(type)) 
    } 

    func get<T>(type: T.Type) -> T { 
     guard let target = map.objectForKey(String(type)) as? T else { 
      fatalError("Not registered") 
     } 
     return target 
    } 
} 
+0

Funktioniert T.Type für eine Protokoll? –

+0

@i_am_jorf, kann von vielen Dingen abhängen. Aber ich kann Ihnen versichern, dass 'services.register (Foo.self, target: Bar())' wie erwartet mit Ihrer Klasse und Ihrem Protokoll funktioniert. Bitte versuche. – OOPer

Verwandte Themen