Ich denke, ich kann Ihre Frage beantworten, aber es ist keine Antwort, die Ihnen gefallen wird.
TL; DR: @objc
Funktionen befinden sich derzeit möglicherweise nicht in Protokollerweiterungen. Sie können stattdessen eine Basisklasse erstellen, obwohl dies keine ideale Lösung ist.
Protokollerweiterungen und Ziel-C
Erstens scheint diese Frage / Antwort ( Kann Swift-Methode für Erweiterungen von Protokollen definiert werden, auf die in Objective-c zugegriffen wird ) darauf hinzudeuten, dass aufgrund der Art und Weise, wie Protokollerweiterungen unter der Haube versendet werden, in Protokollerweiterungen deklarierte Methoden für die objc_msgSend()
Funktion und nicht sichtbar sind sind daher für Objective-C-Code nicht sichtbar. Da die Methode, die Sie in Ihrer Erweiterung definieren möchten, für Objective-C sichtbar sein muss (damit UIKit
sie verwendet werden kann), schreit @objc
sie Sie an, weil Sie sie nicht aufgenommen haben. Sobald Sie sie aufgenommen haben, schreit sie Sie an, weil sie @objc
nicht zulässig ist Protokollerweiterungen. Dies liegt wahrscheinlich daran, dass Protokollerweiterungen derzeit für Objective-C nicht sichtbar sind.
Wir können auch sehen, dass die Fehlermeldung nach dem Hinzufügen den @objc
Status "@objc kann nur mit Mitgliedern von Klassen, @objc-Protokollen und konkreten Erweiterungen von Klassen verwendet werden." Dies ist keine Klasse; Eine Erweiterung eines @ objc-Protokolls ist nicht dasselbe wie in der Protokolldefinition selbst (dh in den Anforderungen), und das Wort "konkret" würde darauf hinweisen, dass eine Protokollerweiterung nicht als konkrete Klassenerweiterung gilt.
Problemumgehung
Leider verhindert dies so ziemlich vollständig, dass Sie Protokollerweiterungen verwenden können, wenn die Standardimplementierungen für Objective-C-Frameworks sichtbar sein müssen. Zuerst dachte ich, dass @objc
Ihre Protokollerweiterung möglicherweise nicht zulässig ist, da der Swift Compiler nicht garantieren kann, dass konforme Typen Klassen sind (obwohl Sie dies speziell angegeben haben UIViewController
). Also habe ich eine class
Anforderung gestellt P1
. Das hat nicht funktioniert.
Vielleicht besteht die einzige Problemumgehung darin, hier einfach eine Basisklasse anstelle eines Protokolls zu verwenden, aber dies ist offensichtlich nicht ganz ideal, da eine Klasse möglicherweise nur eine einzige Basisklasse hat, aber mehreren Protokollen entspricht.
Wenn Sie sich für diesen Weg entscheiden, berücksichtigen Sie bitte diese Frage ( optionale Swift 3 ObjC-Protokollmethode, die in der Unterklasse nicht aufgerufen wird ). Es scheint, dass ein weiteres aktuelles Problem in Swift 3 darin besteht, dass Unterklassen die optionalen Protokollanforderungsimplementierungen ihrer Oberklasse nicht automatisch erben. Die Antwort auf diese Fragen verwendet eine spezielle Anpassung von @objc
, um sie zu umgehen.
Problem melden
Ich denke, dies wird bereits unter denjenigen diskutiert, die an den Swift-Open-Source-Projekten arbeiten, aber Sie können sicher sein, dass sie sich dessen bewusst sind, indem Sie entweder Apples Bug Reporter verwenden , der wahrscheinlich irgendwann den Weg zum Swift Core Team finden würde, oder Swifts Bug Reporter . In beiden Fällen ist Ihr Fehler möglicherweise zu weit gefasst oder bereits bekannt. Das Swift-Team kann auch in Betracht ziehen, wonach Sie suchen, um eine neue Sprachfunktion zu erhalten. In diesem Fall sollten Sie zuerst die Mailinglisten überprüfen .
Aktualisieren
Im Dezember 2016 wurde dieses Problem der Swift-Community gemeldet . Das Problem wird weiterhin als offen mit mittlerer Priorität markiert, aber der folgende Kommentar wurde hinzugefügt:
Dies ist beabsichtigt. Es gibt keine Möglichkeit, die Implementierung der Methode jedem Anwender hinzuzufügen, da die Erweiterung nach der Konformität mit dem Protokoll hinzugefügt werden könnte. Ich nehme an, wir könnten es zulassen, wenn sich die Erweiterung im selben Modul wie das Protokoll befindet.
Da sich Ihr Protokoll jedoch im selben Modul wie Ihre Erweiterung befindet, können Sie dies möglicherweise in einer zukünftigen Version von Swift tun.
Update 2
Im Februar 2017 wurde diese Ausgabe von einem der Mitglieder des Swift Core Teams mit der folgenden Meldung offiziell als "Won't Do" geschlossen :
Dies ist beabsichtigt: Protokollerweiterungen können aufgrund von Einschränkungen der Objective-C-Laufzeit keine @objc-Einstiegspunkte einführen. Wenn Sie NSObject @objc-Einstiegspunkte hinzufügen möchten, erweitern Sie NSObject.
Erweitern NSObject
oder sogar UIViewController
nicht genau das erreichen, was Sie wollen, aber es sieht leider nicht so aus, als würde es möglich werden.
In der (sehr) langfristigen Zukunft können wir möglicherweise die Abhängigkeit von @objc
Methoden vollständig beseitigen , aber diese Zeit wird wahrscheinlich nicht so bald kommen, da Cocoa-Frameworks derzeit nicht in Swift geschrieben sind (und erst dann verfügbar sein können, wenn es einen stabilen ABI hat). .
Update 3
Ab Herbst 2019 wird dies weniger problematisch, da immer mehr Apple-Frameworks in Swift geschrieben werden. Wenn Sie beispielsweise SwiftUI
anstelle von verwenden UIKit
, umgehen Sie das Problem vollständig, da @objc
dies bei der Bezugnahme auf eine SwiftUI
Methode niemals erforderlich wäre .
In Swift geschriebene Apple-Frameworks umfassen:
- SwiftUI
- RealityKit
- Kombinieren
- CryptoKit
Man würde erwarten, dass sich dieses Muster im Laufe der Zeit fortsetzt, da Swift ab Swift 5.0 bzw. 5.1 offiziell ABI- und modulstabil ist.
@objc