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 (vous UIKit
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 une class
exigence P1
. 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é:
C'est prévu. Il n'y a aucun moyen d'ajouter l'implémentation de la méthode à chaque adoptant, puisque l'extension pourrait être ajoutée après la conformité au protocole. Je suppose que nous pourrions l'autoriser si l'extension est dans le même module que le protocole, cependant.
É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:
Ceci est intentionnel: les extensions de protocole ne peuvent pas introduire de points d'entrée @objc en raison des limitations du runtime Objective-C. Si vous souhaitez ajouter des points d'entrée @objc à NSObject, étendez NSObject.
L'extension NSObject
ou même UIViewController
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 de UIKit
, vous évitez complètement le problème car @objc
cela ne serait jamais nécessaire pour faire référence à une SwiftUI
méthode.
Les frameworks Apple écrits en Swift incluent:
- SwiftUI
- RealityKit
- Combiner
- CryptoKit
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.
@objc