2014-09-15 20 views
6

Nadal mam problem ze zrozumieniem niektórych subtelności generycznych w Swift. Zdefiniować następujące typy:Typ nie jest zgodny z protokołem

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

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

    } 
} 

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

viewForValue (2) Teraz zdefiniowane następujące funkcje. Oczekuję, że T będzie UIView, który jest zgodny z protokołem SomeProtocol.

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 
} 

Jednak ja otrzymuję następujący błąd kompilacji kiedy wykonać kod:

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

Wydaje się, że w przypadkach, gdy klauzula nie mogę określić klasę, która nie implementuje protokół . Dlaczego?

Z góry dziękuję.

+1

można spróbować użyć tego: Greg

Odpowiedz

4

viewForValue ma zwrócić klasę, która dziedziczy po UIView i implementuje SomeProtocol. Zdefiniowałeś 2 klasy, które nie mają bezpośredniego związku - po prostu dziedziczą po UIView i implementują SomeProtocol.

Gdy funkcja ma określić typ zwrotu, typ bezpośredniego betonu, którego obie klasy dziedziczą z, to UIView, czyli to, co zwraca viewForValue.

Aby rozwiązać ten problem, trzeba stworzyć bezpośredni i konkretny związek między 2 klasy, tworząc 3. klasa dziedziczy z UIView i wdrażaniu 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) 

Uzupełnienie: czytanie OP poniżej, celem jest dynamiczne tworzenie istniejących klas UIKit dziedziczących po UIView. Tak więc proponowane rozwiązanie nie ma zastosowania.

myślę, że rozszerzenie UIView wdrażając SomeProtocolpowinien pracy:

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 
} 

ale wygląda na to, że to błąd kompilatora. Ten kod na placu zabaw pokazuje komunikat informujący, że:

Komunikacja z serwisem została niespodziewanie przerwana. Usługa zabaw dla dzieci "com.apple.dt.Xcode.Playground" mogła wygenerować dziennik awarii.

natomiast w kompilacji aplikacji iOS nie z powodu usterki segmentacji 11.

+0

starałem się być bardziej ogólne pytanie, ale z moim w moim przypadku klasy objęte są podklasami "UIView": 'UILabel',' UIImageView', więc nie mogę ich dziedziczyć po 'SomeClass'. Zamierzam edytować, aby to odzwierciedlić. – Kamchatka

+0

Zobacz dodatek do mojej odpowiedzi - Myślę, że drugie rozwiązanie powinno działać, ale kod powoduje awarię kompilatora ... – Antonio

+0

Jest to pomocne, dzięki! – Kamchatka

Powiązane problemy