Aperçu:
- J'ai un protocole P1 qui fournit une implémentation par défaut de l'une des fonctions optionnelles d'Objective-C.
- Lorsque je fournis une implémentation par défaut de la fonction optionnelle, il y a un avertissement
Avertissement du compilateur:
Non-'@objc' method 'presentationController(_:viewControllerForAdaptivePresentationStyle:)' does not satisfy optional requirement of '@objc' protocol 'UIAdaptivePresentationControllerDelegate'
Version:
- Rapide: 3
- Xcode: 8 (version publique)
Tentatives effectuées:
- J'ai essayé d'ajouter
@objc
mais n'aide pas
Question:
- Comment résoudre ce problème?
- Y at-il un travail autour ?
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
utilisateur1046037
la source
la source
@objc
Réponses:
Bien que je pense pouvoir répondre à votre question, ce n'est pas une réponse qui vous plaira.
TL; DR:
@objc
fonctions peuvent ne pas être actuellement dans des extensions de protocole. Vous pouvez créer une classe de base à la place, bien que ce ne soit pas une solution idéale.Extensions de protocole et Objective-C
Tout d'abord, cette question / réponse ( méthode Can Swift définie sur les extensions sur les protocoles accessibles dans Objective-c ) semble suggérer qu'en raison de la façon dont les extensions de protocole sont distribuées sous le capot, les méthodes déclarées dans les extensions de protocole ne sont pas visibles pour la
objc_msgSend()
fonction, et ne sont donc pas visibles pour le code Objective-C. Étant donné que la méthode que vous essayez de définir dans votre extension doit être visible par Objective-C (vousUIKit
pouvez donc l' utiliser), elle vous crie de ne pas l'inclure@objc
, mais une fois que vous l'incluez, elle vous crie dessus car elle@objc
n'est pas autorisée dans extensions de protocole. Ceci est probablement dû au fait que les extensions de protocole ne peuvent actuellement pas être visibles par Objective-C.Nous pouvons également voir que le message d'erreur une fois que nous ajoutons les
@objc
états "@objc ne peut être utilisé qu'avec des membres de classes, des protocoles @objc et des extensions concrètes de classes." Ce n'est pas une classe; une extension d'un protocole @objc n'est pas la même chose que d'être dans la définition du protocole elle-même (c'est-à-dire dans les exigences), et le mot «concret» suggérerait qu'une extension de protocole ne compte pas comme une extension de classe concrète.solution de contournement
Malheureusement, cela vous empêche à peu près complètement d'utiliser des extensions de protocole lorsque les implémentations par défaut doivent être visibles pour les frameworks Objective-C. Au début, je pensais que ce
@objc
n'était peut-être pas autorisé dans votre extension de protocole car le compilateur Swift ne pouvait pas garantir que les types conformes seraient des classes (même si vous avez spécifiquement spécifiéUIViewController
). J'ai donc mis uneclass
exigenceP1
. Cela n'a pas fonctionné.La seule solution de contournement est peut-être d'utiliser simplement une classe de base au lieu d'un protocole ici, mais ce n'est évidemment pas complètement idéal car une classe peut n'avoir qu'une seule classe de base mais se conformer à plusieurs protocoles.
Si vous choisissez cette voie, veuillez prendre en compte cette question ( Méthode de protocole facultative Swift 3 ObjC non appelée dans la sous-classe ). Il semble qu'un autre problème actuel dans Swift 3 est que les sous-classes n'héritent pas automatiquement des implémentations d'exigences de protocole facultatives de leur superclasse. La réponse à ces questions utilise une adaptation spéciale de
@objc
pour la contourner.Signaler le problème
Je pense que cela est déjà discuté parmi ceux qui travaillent sur les projets open source Swift, mais vous pouvez être sûr qu'ils sont au courant soit en utilisant le Bug Reporter d'Apple , qui finirait probablement par arriver à l'équipe Swift Core, ou en utilisant le bug Reporter de Swift . Cependant, l'un ou l'autre de ces problèmes peut trouver votre bogue trop large ou déjà connu. L'équipe Swift peut également considérer ce que vous recherchez comme une nouvelle fonctionnalité linguistique, auquel cas vous devriez d'abord consulter les listes de diffusion .
Mettre à jour
En décembre 2016, ce problème a été signalé à la communauté Swift. Le problème est toujours marqué comme ouvert avec une priorité moyenne, mais le commentaire suivant a été ajouté:
Étant donné que votre protocole se trouve dans le même module que votre extension, vous pourrez peut-être le faire dans une future version de Swift.
Mise à jour 2
En février 2017, ce numéro a été officiellement clos en tant que "Won't Do" par l'un des membres de l'équipe Swift Core avec le message suivant:
L'extension
NSObject
ou mêmeUIViewController
n'accomplira pas exactement ce que vous voulez, mais il ne semble malheureusement pas que cela devienne possible.Dans un avenir (très) long terme, nous pourrons peut-être éliminer
@objc
complètement la dépendance aux méthodes, mais ce moment ne viendra probablement pas de si tôt car les frameworks Cocoa ne sont pas actuellement écrits en Swift (et ne peuvent pas l'être tant qu'ils n'ont pas un ABI stable) .Mise à jour 3
À partir de l'automne 2019, cela devient moins un problème car de plus en plus de frameworks Apple sont écrits en Swift. Par exemple, si vous utilisez à la
SwiftUI
place deUIKit
, vous évitez complètement le problème car@objc
cela ne serait jamais nécessaire pour faire référence à uneSwiftUI
méthode.Les frameworks Apple écrits en Swift incluent:
On pourrait s'attendre à ce que ce modèle se poursuive dans le temps maintenant que Swift est officiellement ABI et module stable à partir de Swift 5.0 et 5.1, respectivement.
la source
Swift 4
aucune autre alternative pour le moment.Je viens de rencontrer cela après avoir activé la `` stabilité du module '' (l'activation de `` Créer des bibliothèques pour la distribution '') dans un cadre rapide que j'utilise.
Ce que j'avais était quelque chose comme ça:
La fonction dans l'extension avait ces erreurs:
La méthode d'instance '@objc' dans l'extension de la sous-classe de 'LessAwesomeClass' nécessite iOS 13.0.0
Non - La méthode '@ objc' 'niceDelegateFunc' ne satisfait pas l'exigence du protocole '@objc' 'GreatDelegate'
Le déplacement des fonctions dans la classe plutôt que dans une extension a résolu le problème.
la source
Voici une autre solution de contournement. J'ai également rencontré ce problème et je ne peux pas encore passer d'UIKit à SwiftUI. Déplacer les implémentations par défaut dans une classe de base commune n'était pas non plus une option pour moi. Mes implémentations par défaut étaient assez étendues, donc je ne voulais vraiment pas que tout ce code soit dupliqué. La solution de contournement que j'ai fini par utiliser était d'utiliser des fonctions wrapper dans le protocole, puis d'appeler simplement ces fonctions à partir de chaque classe. Pas joli, mais peut-être mieux que l'alternative, selon la situation. Votre code ressemblerait alors à ceci:
la source