Überblick:
- Ich habe ein Protokoll P1, das eine Standardimplementierung einer der optionalen Objective-C-Funktionen bietet.
- Wenn ich eine Standardimplementierung der optionalen Funktion bereitstelle, wird eine Warnung angezeigt
Compiler Warnung:
Non-'@objc' method 'presentationController(_:viewControllerForAdaptivePresentationStyle:)' does not satisfy optional requirement of '@objc' protocol 'UIAdaptivePresentationControllerDelegate'
Ausführung:
- Swift: 3
- Xcode: 8 (Veröffentlichung)
Versuche gemacht:
- Versucht hinzuzufügen
@objc
, hilft aber nicht
Frage:
- Wie löse ich das?
- Gibt es eine Lösung?
Code:
@objc protocol P1 : UIAdaptivePresentationControllerDelegate {
}
extension P1 where Self : UIViewController {
func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
return UIViewController()
}
}
class A : UIViewController, P1 {
}
swift
swift3
swift-protocols
user1046037
quelle
quelle
@objc
Antworten:
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 (damitUIKit
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 habenUIViewController
). Also habe ich eineclass
Anforderung gestelltP1
. 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:
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 :
Erweitern
NSObject
oder sogarUIViewController
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 verwendenUIKit
, umgehen Sie das Problem vollständig, da@objc
dies bei der Bezugnahme auf eineSwiftUI
Methode niemals erforderlich wäre .In Swift geschriebene Apple-Frameworks umfassen:
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.
quelle
Swift 4
keiner anderen Alternative.Ich bin gerade darauf gestoßen, nachdem ich 'Modulstabilität' (Aktivieren von 'Bibliotheken für die Verteilung erstellen') in einem von mir verwendeten schnellen Framework aktiviert habe.
Was ich hatte, war ungefähr so:
Die Funktion in der Erweiterung hatte folgende Fehler:
Die Instanzmethode '@objc' in Erweiterung der Unterklasse von 'LessAwesomeClass' erfordert iOS 13.0.0
Nicht-'@ objc'-Methode' niceDelegateFunc 'erfüllt nicht die Anforderung des' @objc'-Protokolls 'GreatDelegate'
Durch Verschieben der Funktionen in die Klasse und nicht in eine Erweiterung wurde das Problem behoben.
quelle
Hier ist eine weitere Problemumgehung. Ich bin auch auf dieses Problem gestoßen und kann noch nicht von UIKit zu SwiftUI wechseln. Das Verschieben der Standardimplementierungen in eine gemeinsame Basisklasse war für mich ebenfalls keine Option. Meine Standardimplementierungen waren ziemlich umfangreich, so dass ich wirklich nicht wollte, dass der gesamte Code dupliziert wird. Die Problemumgehung, die ich letztendlich verwendet habe, bestand darin, Wrapper-Funktionen im Protokoll zu verwenden und diese Funktionen dann einfach aus jeder Klasse aufzurufen. Nicht schön, aber je nach Situation vielleicht besser als die Alternative. Ihr Code würde dann ungefähr so aussehen:
quelle