2015-11-11 9 views
7

Ich versuche, ein einfaches Dependency Injection-System für unsere App in Swift, für 2 Tage jetzt zu machen. Ich bin flexibel zu welcher Lösung, aber ich möchte etwas, damit ich sagen kann "gib mir eine Instanz von etwas, das diesem Protokoll entspricht" und der tatsächlich zurückgegebene Typ kann was auch immer sein, solange es dem besagten Protokoll entspricht. Ich habe sehr viele Dinge einschließlich Generika versucht, aber gelungen, um herauszufinden, dass das nicht wirklich so jetzt arbeitet ich bin bis auf die nackten Grundlagen, so etwas wie diese (?):Überprüfen Sie, ob Klasse entspricht Protokoll

protocol AProtocol { 

} 

class AClass: AProtocol { 

} 

class MyDiThing { 
    public static func objectConformingTo(aProtocol: Any) -> Any? { 
     // And here I want to do something like 
     if AClass is aProtocol { 
      return AClass() 
     } 
     return nil 
    } 
} 

// The calling code .. 
let aObject = MyDIThing.objectConformingTo(AProtocol) 

Es ist nicht schön, ich Wissen Sie, aber im Moment bin ich nicht so wählerisch in Bezug auf Leistung/schlechten Code, solange es das Entkopplungsproblem löst (und vorzugsweise in der MyDIThing-Klasse enthalten sein kann). Wenn das in swift unmöglich ist, bin ich offen für andere Lösungen. Ich habe ähnliche Lösungen mit objective-c mit gutem Erfolg verwendet, nur mit einem Wörterbuch mit Schlüsseln als NSStringFromProtocol und Werten als Klasse, Subskribierung des Wörterbuchs mit dem eingehenden Protokoll und Instanziierung der Klasse. Super einfach. In swift fühlt es sich unmöglich an!

Antwort

4

Wenn Sie Obj-c importieren, dann können Sie etwas tun, wie Sie es gewohnt sind.

Sonst ist es schwer, weil Protokolle nicht auf die gleiche Weise existieren. Stellen Sie sich ein registrierungsbasiertes System für Ihre Fabrik vor. Jede Ihrer Klassen würde sich selbst registrieren, indem sie eine Funktion oder eine Schließung bereitstellt, die aufgerufen werden kann, um eine neue Instanz dieser Klasse zurückzugeben, und die Registrierung erfolgt anhand einer Zeichenfolge oder eines anderen Typs von Kennung. Hier wäre es gut, einen Protokolltyp zu haben, aber in obj-c hast du das Gleiche mit einer String-Konvertierung gemacht. Sie könnten sich gegen alles registrieren, was Equatable ist, um die Dinge sehr allgemein zu halten.

+8

'wenn foo = bar wie? MyProtocol {/ * bar entspricht dem Protokoll ... foo ist vom Typ MyProtocol und die Methoden können darauf aufgerufen werden * /} ' – nhgrif

+0

Ich habe den Registrierungs-basierten schnellen Ansatz mit einer Enum als Schlüssel und einem Closure als Wert gemacht. Funktioniert gut. –

7

Die von nhgrif gegeben Kommentar ist die richtige Antwort für Swift 2. sollten Sie eine optionale Bindung verwenden:

if let aObjectWithAProtocol = aObject as? AProtocol { 
    // object conforms to protocol 
    someObject.someFunction(aObjectWithAProtocol) 
} else { 
    // object does not conform to protocol 
} 

Diese if let something = obj as? type Anweisung optional und prüft Bindung aufgerufen wird, wenn das Objekt sein kann Typ-gegossen zu dem angegebenen Typ/Klasse/Protokoll/....

Wenn ja, können Sie die optionale (as?) oder Kraft unwrap nutzen (as!) das Objekt.

0

Diese Funktion wird Ihre Anforderung perfekt erfüllen:

bool _swift_typeIsTargetType(id sourceType, id targetType)

Es kann eine schnelle Art der Zieltyp ist (ist die gleiche Typ oder Unterklasse, oder entspricht das Ziel-Protokoll), funktioniert wie is prüfen, ob Betreiber in swift. Aber es ist für einen Typ, nicht für eine Instanz:

let sourceType: Any.Type = type(of: self) 
let targetType: Any.Type = AnyProtocol.self 
let result = _swift_typeIsTargetType(sourceType, targetType) 

Es privaten APIs in libswiftCore.dylib verwendet, finden Sie swift Quellcode Casting.cpp:

bool _conformsToProtocols(const OpaqueValue *value, const Metadata *type, const ExistentialTypeMetadata *existentialType, const WitnessTable **conformances) 

Optional Bindung ist nicht gleich. Es kann auch die Konformität überprüfen, aber Sie können nicht dynamisch die Art geben zu überprüfen:

let targetType: Any.Type = AnyProtocol.self 
//error: use of undeclared type: 'targetType' 
if let _ = aObject as? targetType { 
    // object conforms to protocol 
} else { 
    // object does not conform to protocol 
} 

Diese Funktion ist in ZIKRouter verwendet wird. Es ist ein Modul-Router und auch ein Dependency-Injection-Framework. Es verwendet Protokoll, um Module zu entdecken und Abhängigkeiten zu injizieren.Sie können es versuchen, wenn Sie etwas wie "Finden eines Moduls, das einem Protokoll entspricht" machen möchten.

Verwandte Themen