web-dev-qa-db-fra.com

La méthode non '@ objc' ne satisfait pas l'exigence facultative du protocole '@objc'

Vue d'ensemble:

  • 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 faites:

  • J'ai essayé d'ajouter @objc mais n'aide pas

Question:

  • Comment j'ai résolu ceci?
  • 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 {

}
85
user1046037

Bien que je pense pouvoir répondre à votre question, ce n’est pas une réponse que vous aimerez.

TL; DR: Les fonctions @objc Peuvent ne pas être actuellement dans les 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

Premièrement, cette question/réponse ( la méthode Can Swift peut être définie sur les extensions de protocoles consultées dans Objective-c ) semble suggérer qu'en raison de la façon dont les extensions de protocole sont envoyées sous le capot, les méthodes déclarées dans le protocole, les extensions ne sont pas visibles par la fonction objc_msgSend() et ne sont donc pas visibles par le code Objective-C. Puisque la méthode que vous essayez de définir dans votre extension doit être visible pour Objective-C (pour que UIKit puisse l'utiliser), il vous hurle de ne pas inclure @objc, Mais une fois que vous le faites incluez-le, il vous hurle dessus parce que @objc n'est pas autorisé dans les extensions de protocole. Ceci est probablement dû au fait que les extensions de protocole ne sont actuellement pas visibles par Objective-C.

Nous pouvons également constater que le message d'erreur une fois que nous avons ajouté @objc Indique que "@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 à un protocole @objc n’est pas identique à la définition de protocole elle-même (c’est-à-dire aux exigences), et le mot "concret" suggérerait qu’une extension de protocole ne compte pas comme une extension de classe concrète.

Workaround

Malheureusement, cela vous empêche 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 peut-être que @objc N'était 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écifié spécifiquement UIViewController) . J'ai donc mis une exigence class sur P1. Cela n'a pas fonctionné.

La seule solution possible consiste peut-être simplement à utiliser ici une classe de base au lieu d'un protocole, mais ce n'est évidemment pas tout à fait idéal, car une classe ne peut avoir qu'une seule classe de base mais se conformer à plusieurs protocoles.

Si vous choisissez d'emprunter cette voie, veuillez répondre à cette question ( Swift 3 ObjC Protocole facultatif Méthode non appelée dans la sous-classe ). Il semble qu'un autre problème actuel dans Swift 3 réside dans le fait que les sous-classes n'héritent pas automatiquement des implémentations des exigences de protocole facultatives de leur super-classe. La réponse à cette question utilise une adaptation spéciale de @objc Pour la contourner.

Signaler le problème

Je pense que cela fait déjà l'objet de discussions entre ceux qui travaillent sur les projets open source Swift, mais vous pouvez être sûr qu'ils sont au courant en utilisant soit Bug Reporter d'Apple , ce qui finira probablement par se frayer un chemin. à l'équipe principale Swift, ou rapporteur de bugs de Swift . Cependant, l’un ou l’autre de ceux-ci 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. Dans ce cas, vous devez d’abord effectuer une vérification les listes de diffusion .

Mise à jour

En décembre 2016, ce problème a été signalé à la communauté Swift. La question est toujours marquée comme ouverte avec une priorité moyenne, mais le commentaire suivant a été ajouté:

Ceci est destiné. Il n’ya aucun moyen d’ajouter l’implémentation de la méthode à chaque adoptant, car l’extension pourrait être ajoutée après la conformité au protocole. Je suppose que nous pourrions l’autoriser si l’extension se trouve dans le même module que le protocole.

Puisque votre protocole est 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 problème était officiellement clos comme "ne le ferait pas" par l'un des membres de l'équipe de Swift avec le message suivant:

Cela est intentionnel: les extensions de protocole ne peuvent pas introduire de points d'entrée @objc en raison des limitations de l'exécution Objective-C. Si vous souhaitez ajouter des points d'entrée @objc à NSObject, développez NSObject.

L'extension de NSObject ou même de UIViewController n'accomplira pas exactement ce que vous voulez, mais malheureusement, il ne semble pas que cela deviendra possible.

À très long terme, nous pourrons peut-être totalement nous passer de la méthode @objc, Mais ce temps ne sera probablement pas si tôt, car les frameworks Cocoa ne sont pas écrits dans Swift ( et ne peut pas être avant d'avoir un ABI stable).

160
Matthew Seaman