2014-09-15 15 views
6

Ich habe immer noch Probleme, einige Feinheiten von Generika in Swift zu verstehen. I definieren die folgenden Typen:Typ entspricht nicht dem Protokoll

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

class ProtocolLabel : UILabel, SomeProtocol { 
    func setValue(value: Int) { 

    } 
} 

class ProtocolImageView : UIImageView, SomeProtocol { 
    func setValue(value: Int) { 
    } 
} 

viewForValue (2) nun definiert I die folgende Funktion. Ich erwarte, dass T eine UIView ist, die dem Protokoll SomeProtocol entspricht.

func viewForValue<T where T: SomeProtocol, T: UIView>(param: Int) -> UIView { 
    var someView: T 
    if param > 0 { 
     someView = ProtocolLabel() as T 
    } else { 
     someView = ProtocolImageView() as T 
    } 
    someView.setValue(2) 
    someView.frame = CGRectZero 
    return someView 
} 

Allerdings bin ich die folgende Compiler-Fehler bekommen, wenn ich den Code ausführen:

viewForValue(2) // <-- Type 'UIView' does not conform to protocol 'SomeProtocol' 

Es scheint, dass in der Klausel, wo ich nicht eine Klasse angeben, die nicht das Protokoll nicht umsetzen . Warum das?

Vielen Dank im Voraus.

+1

Können Sie versuchen, diese verwenden: Greg

Antwort

4

viewForValue soll eine Klasse zurückgeben, die von UIView erbt und implementiert SomeProtocol. Sie haben 2 Klassen ohne direkte Beziehung definiert - sie erben nur von UIView und implementieren SomeProtocol.

Wenn die Funktion den Rückgabetyp bestimmen muss, ist der direkte konkrete Typ, von dem beide Klassen erben, UIView, also wird viewForValue zurückgegeben.

Um das Problem zu beheben, haben Sie einen direkten und konkreten Zusammenhang zwischen den zwei Klassen erstellen, indem Sie eine dritte Klasse von UIView erbt die Erstellung und Implementierung SomeProtocol:

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

class SomeClass: UIView, SomeProtocol { 
    func setValue(value: Int) { 

    } 
} 

class SomeSubclass : SomeClass { 
} 

class SomeOtherSubclass : SomeClass { 
} 

func viewForValue<T where T: SomeProtocol, T: SomeClass>(param: Int) -> T { 
    var someView: T 
    if param > 0 { 
     someView = SomeSubclass() as T 
    } else { 
     someView = SomeOtherSubclass() as T 
    } 
    someView.setValue(2) 
    someView.frame = CGRectZero 
    return someView 
} 

viewForValue(2) 

Addendum: das Lesen OP-Kommentar unten, der Zweck besteht darin, vorhandene UIKit-Klassen, die von UIView erben, dynamisch zu instanziieren. Die vorgeschlagene Lösung gilt also nicht.

Ich denke, dass UIView durch die Umsetzung SomeProtocolsollte Arbeit erstreckt:

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

extension UIView : SomeProtocol { 
    func setValue(value: Int) { 
    } 
} 

func viewForValue<T where T: SomeProtocol, T: UIView>(param: Int) -> UIView { 
    var someView: T 
    if param > 0 { 
     someView = UILabel() as T 
    } else { 
     someView = UIImageView() as T 
    } 
    someView.setValue(2) 
    someView.frame = CGRectZero 
    return someView 
} 

aber es sieht aus wie ein Compiler Fehler ist. Dieser Code in einem Spielplatz zeigt eine Nachricht an:

Die Kommunikation mit dem Spielplatzdienst wurde unerwartet unterbrochen. Der Spielplatzdienst "com.apple.dt.Xcode.Playground" hat möglicherweise ein Absturzprotokoll erstellt.

während in einer iOS-Anwendung Kompilierung schlägt fehl aufgrund eines Segmentierungsfehler 11.

+0

Ich habe versucht, mit meiner Frage mehr generisch zu sein, aber In meinem Fall sind die beteiligten Klassen 'UIView'-Unterklassen:' UILabel', 'UIImageView', sodass ich sie nicht von einer' SomeClass' erben lassen kann. Ich werde bearbeiten, um das zu reflektieren. – Kamchatka

+0

Siehe Ergänzung zu meiner Antwort - Ich denke, die 2. Lösung sollte funktionieren, aber der Code bringt den Compiler zum Absturz ... – Antonio

+0

Das ist hilfreich, danke! – Kamchatka

Verwandte Themen