2015-08-05 7 views
7

Ich arbeite an einem Swift (v1.2) Projekt, das zwei UIViews enthält. MyView und MyViewSubclass.Ein Superklassen-Delegat in Swift überschreiben

MyView hat einen Delegierten, die ich in MyViewSubclass außer Kraft setzen möchten ein Sub-Protokoll zu sein, ähnlich wie UITableViews haben eine UITableViewDelegate die dem Super UIScrollViewDelegate entspricht auch.

Meine erste Idee war, die Superklasseneigenschaft zu überschreiben, aber diese verursacht einen Compilerfehler, da eine Unterklasse eine Superklasseneigenschaft mit einem anderen Typ nicht überschreiben kann.

// Example throws a compiler error. Can't override property with different type 

class MyView : UIView { 
    weak var delegate : MyViewDelegate? 
} 

class MyViewSubclass : MyView { 
    override weak var delegate : MyViewSubclassDelegate? // Compiler error 
} 

protocol MyViewDelegate { 
    func someFunc() 
} 

protocol MyViewSubclassDelegate : MyViewDelegate { 
    //func someFunc() Edit: redefinition not necessary, thanks @Rob! 
    func someOtherFunc() 
} 

Meine zweite Idee war, die impliziten Getter und Setter-Methoden der Delegate-Eigenschaft zu überschreiben. Die Unterklasse könnte einen Getter haben, der ein MyViewSubclassDelegate nimmt und auf das MyViewDelegate Protokoll umwandelt, so dass die Eigenschaft selbst nicht überschrieben werden muss.

Diese Methode führt auch zu einem Compilerfehler. Die Accessoren können die Superklassenmethoden nicht "überschreiben", da sie unterschiedliche Methodensignaturen haben und nicht einfach deklariert werden können, weil ihre Namen mit den Superklassen-Sätzen in Konflikt stehen.

// Example throws a compiler error. Can't declare function with a conflicting name 

class MyViewSubclass : MyView { 
    func setDelegate (newValue : MyViewSubclassDelegate) { // Compiler error 
     super.delegate = newValue as? MyViewDelegate 
    } 

    func getDelegate() -> MyViewSubclassDelegate { // Compiler error 
     return super.delegate as? MyViewSubclassDelegate 
    } 
} 

ich die Unterklasse die Getter und Setter für die Oberklasse, und speichern nur die Delegierten in einer separaten Unterklasse Eigenschaft, die funktioniert, aber dann die Unterklasse haben könnte außer Kraft setzen aussehen wird es zugeordnet werden soll MyViewDelegate, wenn es wirklich eine MyViewSubclassDelegate zugeordnet werden muss, die in der Zukunft zu ernsthaften Verwirrung führen könnte.

// Example works, but it is unclear that MyViewSubclass's delegate should be 
// assigned a MyViewSubclassDelegate 

class MyViewSubclass : MyView { 
    private weak var _subclassDelegate : MyViewSubclassDelegate? 

    override weak var delegate : MyViewDelegate? { // Ambiguous type 
     didSet { 
      _subclassDelegate = delegate as? MyViewSubclassDelegate 
     } 
    } 
} 

Ich weiß etwas zumindest ähnlich möglich ist, weil Klassen wie UITableView und UICollectionView scheinen zu tun, was ich will, aber sie sind auch in Objective-C, statt Swift geschrieben, so dass die Besonderheiten das, was die Sprache erlaubt möglicherweise anders.

Gibt es eine Möglichkeit, eine Swift-Unterklasse die Eigenschaft einer Superklasse mit einem Untertyp überschreiben zu lassen?

+0

Danke für den Vorschlag! Das Erben von Protokollen wird funktionieren (und ich tue das im Beispiel), aber es endet immer noch mit dem gleichen Problem wie in Beispiel 3, wo der Delegat für die Unterklasse erscheint, als ob es das Superprotokoll wäre, wo das Unterprotokoll ist Delegierter ist erforderlich. Für jetzt, ich denke, ich werde bleiben mit zwei separate Parameter wie in Ihrem ersten Kommentar, bis ich eine Lösung ein bisschen mehr wie die von UITableViewDelegate verwendet finden kann. –

+0

@Rob Vielleicht ist es nur mir schwierig. Mein Hauptkritikpunkt bei dieser Lösung ist, dass Sie die Protokollkonformität nicht streng durchsetzen können. Wenn MyViewSubclass einen Delegaten vom Typ 'MyViewDelegate' hat, gibt es keine Möglichkeit sicherzustellen, dass' (Delegate als? MyViewSubclassDelegate) ?. someOtherFunc() 'jemals ausgeführt wird. Der Ansicht könnte stattdessen die Superklasse zugewiesen werden, und die optionale Kette würde im Stillen ausfallen. Sie könnten auch prüfen, ob es auf den Selektor reagiert, aber dann haben Sie eine Laufzeitbeschränkung, anstatt der Kompilierzeit. –

Antwort

6

Es ist nicht ideal, aber wenn ein Protokoll von dem anderen vererbt wird, anstatt verschiedene Arten verwendet, die gleiche Art verwenden, sondern implementieren Validierung in didSet:

class MyView : UIView { 

    /// The `MyViewDelegate` delegate 

    weak var delegate: MyViewDelegate? 
} 

class MyViewSubclass: MyView { 

    /// The `MyViewSubclassDelegate` delegate. 
    /// 
    /// **Note: This must be MyViewSubclassDelegate** 

    override weak var delegate: MyViewDelegate? { 
     didSet { 
      assert(delegate == nil || delegate is MyViewSubclassDelegate, "The delegate of MyViewSubclass must be of type `MyViewSubclassDelegate`") 
     } 
    } 
} 

Es ist unelegant, aber zumindest Sie Ich bekomme einen sofortigen Laufzeitfehler, der das Problem auf den Programmierer aufmerksam macht. Und indem Sie den Kommentar /// einbeziehen, wird er auch in der Schnellhilfe angezeigt.

-

Alternativ können Sie mehr radikale Veränderungen annehmen, z.B.etwas wie delegate und peoplePickerDelegate Eigenschaften von ABPeoplePickerNavigationController, wo der Unterklasse-Delegat über eine andere Eigenschaft angegeben wird.

+0

Danke! Bis jetzt ist das das Beste, was mir einfällt! –

Verwandte Themen