Wie man verlangt, dass ein Protokoll nur von einer bestimmten Klasse übernommen werden kann


88

Ich möchte dieses Protokoll:

protocol AddsMoreCommands {
     /* ... */
}

Nur von Klassen zu übernehmen, die von der Klasse erben UIViewController. Auf dieser Seite kann ich angeben, dass sie nur von einer Klasse (im Gegensatz zu einer Struktur) schriftlich übernommen wird

protocol AddsMoreCommands: class {
}

aber ich kann nicht sehen, wie ich verlangen soll, dass es nur von einer bestimmten Klasse übernommen wird. Auf dieser Seite wird später über das Hinzufügen von whereKlauseln zu Protokollerweiterungen gesprochen, um die Konformität zu überprüfen, aber ich kann auch nicht sehen, wie dies angepasst werden kann.

extension AddsMoreCommands where /* what */ {
}

Gibt es eine Möglichkeit, dies zu tun? Vielen Dank!

Antworten:


113
protocol AddsMoreCommands: class {
    // Code
}

extension AddsMoreCommands where Self: UIViewController {
    // Code
}

4
Ich hatte es so fast ... Ich schrieb selfstatt Self:-( Vielen Dank, das funktioniert gut!
emrys57

Für mich verursacht dies eine gewisse syntaktische Fremdheit, wenn ich dies in Verbindung mit Casting verwende.
Chris Prince

3
Dies funktioniert nicht, wenn Sie eine Eigenschaft in das Protokoll aufnehmen müssen, da Erweiterungen keine gespeicherten Eigenschaften enthalten können.
Shim

1
Es kann Eigentum gespeichert haben, das Sie nur verwenden müssen: objc_getAssociatedObject (self, & KeyName) as? PropertyType
Michał Ziobro

Dies erfordert auch Casting, wenn eine let / var-Deklaration einen Typ hat, AddsMoreCommandsaber eine Methode, an die Sie sie übergeben, einenUIViewController
GoatInTheMachine

77

Dies kann auch ohne Erweiterung erreicht werden:

protocol AddsMoreCommands: class where Self: UIViewController {
   // code
}

EDITED 2017/11/04 : Wie Zig betonte, scheint dies eine Warnung auf Xcode 9.1 zu generieren. Derzeit wurde ein Problem mit dem Swift-Projekt gemeldet (SR-6265). , um die Warnung zu entfernen. Ich werde sie im Auge behalten und die Antwort entsprechend aktualisieren.

EDITED 2018/09/29 : classWird benötigt, wenn die Variable, in der die Instanz gespeichert wird, schwach sein muss (z. B. ein Delegat). Wenn Sie keine schwache Variable benötigen, können Sie die weglassen classund einfach Folgendes schreiben, und es wird keine Warnung angezeigt:

protocol AddsMoreCommands where Self: UIViewController {
   // code
}

5
Wie zufällig ist es, dass ich auf eine zwei Jahre alte Frage geklickt habe und eine perfekte Lösung gefunden habe, die vor einer Stunde veröffentlicht wurde Oscar
Oscar Apeland

Xcode 9.1 warnt mich jetzt vor diesem Sprichwort: Redundante Layoutbeschränkung 'Self': 'AnyObject'. Layouteinschränkung Einschränkung 'Self': 'AnyObject' hier impliziert. Das Ändern meines Codes in das Format der akzeptierten Antwort scheint besser zu sein.
Zig

2
Ab Xcode 9.1 werden jetzt nur noch Klassenprotokolle AnyObjectanstelle von verwendet class. protocol AddsMoreCommands: AnyObject where Self: UIViewController { // code }
Dodgio

@ Dodgio immer noch die gleiche Warnung mitAnyObject
Rgkobashi

1
@ DávidPásztor Sie haben Recht, aber wenn Sie es für ein Strukturmuster wie Delegation verwenden möchten, um die Eigenschaft schwach zu machen, ist es notwendig, "Klasse" explizit hinzuzufügen :)
rgkobashi

48

Aufgrund eines Problems in der vorherigen Antwort kam ich zu folgender Erklärung:

protocol AddsMoreCommands where Self : UIViewController { 
    // protocol stuff here  
}

Keine Warnungen in Xcode 9.1


5
Korrigieren Sie mich, wenn ich falsch liege, aber das Problem mit der obigen Lösung (die in Xcode 9.1 und höher eine Warnung generiert) ist, dass Sie den Delegaten nicht als schwach deklarieren können.
Kyle Goslan

Wenn ich diese Lösung mit Swift 4.1 verwende, muss ich auch die Eigenschaften der AddsMoreCommandsUIViewController
Elemente umwandeln

8
Um die Typumwandlung zu vermeiden, können Sie dies tun:typealias AddsMoreCommandsViewController = UIViewController & AddsMoreCommands
plu

33

In Swift 5 können Sie dies erreichen, indem Sie:

protocol AddsMoreCommands: UIViewController {
     /* ... */
}

Sehr praktisch.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.