2016-04-07 3 views
1

Ich möchte eine Methode implementieren, die nur Klassen unterstützte Protokolle nahm. Zu diesem Zweck habe ich ein Protokoll definiert:Swift: Limit-Klassen nur unterstützt Protokoll

protocol TestProt { 
    func testMe() -> String 
} 

Lassen Sie uns eine Klassendeklaration tun:

class TestClass: TestProt { 
    func testMe() -> String { 
     return "test" 
    } 
} 

Aber, wie ich Register Klasse implementieren kann, um nur Klassen unterstützt TestProt?

class FabricaClass { 
    // it is func take any classes :(
    func registerMe(context: MyContext, class: AnyClass) -> String { 
    } 
    // i want something like this =) 
    // to the method took only classes supported protocols 
    // but it don't work for swift... 
    func registerMe(context: MyContext, class: AnyClass <TestProt>) -> String { 
    } 

} 

UPD: Antwort

protocol TestProt { 
    static func testMe() -> String 
} 

class TestClass: TestProt { 
    class func testMe() -> String { 
     return "test" 
    } 
} 

class MyContext { 
} 

class FactoryClass { 
    init<T: TestProt>(context: MyContext, regClass: T.Type) { 
     regClass.testMe() 
    } 
} 

let context = MyContext() 
let factory = FactoryClass(context: context, regClass: TestClass.self) 

Dank für @dfri

+0

Worth suchen http://stackoverflow.com/a/24051850/2710486 – zcui93

Antwort

3

Sie benötigen einen generischen Typ in Ihrer Funktion schließen und eine Typeinschränkung zu dieser Gattung hinzufügen, wobei der Typ Einschränkung stellt sicher, dass die Typen Verwendung der Funktion entsprechen dem Protokoll als Typeinschränkung verwendet zu machen. Z.B .:

/* add :class keyword to constrain this protocol only 
to be conformable to by class types */ 
protocol ProtocolOnlyIntendedForClasses: class { 
    func foo() -> String 
    init() // to make use of metaType for initialization in generic function 
} 

class Foo: ProtocolOnlyIntendedForClasses { 
    func foo() -> String { 
     return "foo" 
    } 
    required init() { } 
} 

/* function taking class type objects that conforms 
    to ProtocolOnlyIntendedForClasses */ 
func bar<T: ProtocolOnlyIntendedForClasses>(foo: T) -> String { 
    return foo.foo() 
} 

/* as above, but making use of metatype representation 
    of generic T rather than an instance of it */ 
func barWithMetaType<T: ProtocolOnlyIntendedForClasses>(fooMetaType: T.Type) -> String { 

    // .. 

    return fooMetaType.init().foo() 
} 

/* example usage */ 
let foo = Foo() 
let baz = bar(foo) 
let bax = barWithMetaType(Foo.self) 
print(baz, bax) // foo foo 

Wo wir die Art der T als Metatyp mit T.Type zugegriffen haben.

auf Ihre speziellen Beispiel angewendet:

// ... 

class FabricaClass { 

    // ... 

    // as specified in comments, you want the class (meta)type, 
    // rather than an instance of it 
    func registerMe<T: TestProt>(context: MyContext, someMetaType: T.Type) -> String { 

     // ... 

     return someMetaType.init().testMe() 
      // given that you added blueprint for 'init()' in protocol TestProt 
    } 

} 

Hinweis, dass jedoch die Verwendung Metatypen (someMetaType in registerMe(..) Funktion oben) recht begrenzt ist, und nicht äquivalent zur Verwendung geben Sie eine statische (Kompilierung Zeit bekannt) .


Weitere Einzelheiten finden Sie unter

+0

Nein, ich brauche ** Klasse ** in Verfahren erhalten, nicht Instans –

+0

@EvGeniyIlyin aktualisiert Antwort mit _metatypes_ vom Typ eher generisch eingeschränkt als Instanzen des Typs eingeschränkt generisch. – dfri

+0

danke! Du sparst mich =) –

0

Haben Sie dies versuchen?

func registerMe(context: MyContext, class: TestProt) -> String { 
} 
0

Ich bin nicht sicher, ob Sie es wirklich auf Klassen beschränkt wollen oder ob Sie gemeint:

wie i-Register-Klasse implementieren kann, um nur Typen TestProt unterstützt?

Wie auch immer, wenn Sie auf Klassen beschränken wollen, sehen Sie @ dfris Antwort. Für den Rest der Frage gibt es zwei Möglichkeiten. Es gibt den generischen Ansatz:

fund registerMe<T: TestProt>(context: MyContext, class:T) -> String {} 

wobei T den Typ annimmt, an dem es übergeben wird. Wenn diese Methode beispielsweise einen Typ des gleichen Typs wie die Klasse zurückgeben würde (anstatt String), würde der Compiler wissen, dass eine TestClass Instanz zurückgegeben wurde.Aber die andere Art und Weise:

func registerMe(context: MyContext, class:TestProt) -> String {} 

Sie TestProt werfen, so dass während des dynamicType noch TestClass zur Laufzeit sein wird, gibt es keine Möglichkeit für Sie, die gleiche Art zurück in Bezug auf die Methode übergeben wurde. Sie können die Instanz nur als Instanz zurücksenden, die TestProt entspricht. Und dann müssten Sie zurück in die eigentliche Klasse werfen.