Le correctif est correct - il n'y a rien à changer dans le sélecteur pour que la méthode à laquelle il se réfère soit exposée à l'Objective-C.
La raison d'être de cet avertissement est la suivante SE-0160 . Avant Swift 4, internal
ou plus compatible avec l'Objective-C NSObject
ont été déduites comme étant des classes @objc
et donc exposées à l'Objective-C, ce qui permet de les appeler à l'aide de sélecteurs (l'exécution de l'Obj-C étant nécessaire pour rechercher l'implémentation de la méthode pour un sélecteur donné).
Cependant, dans Swift 4, ce n'est plus le cas. Seules les déclarations très spécifiques sont maintenant déduites comme étant des @objc
par exemple, les dérogations aux @objc
des méthodes, des mises en œuvre de @objc
les exigences du protocole et les déclarations avec des attributs qui impliquent @objc
, tels que @IBOutlet
.
La motivation de cette démarche, telle qu'elle est détaillée dans la proposition susmentionnée L'objectif de ce programme est tout d'abord d'éviter les surcharges de méthodes dans le domaine de la santé. NSObject
les classes qui héritent d'une autre classe n'entrent pas en collision les unes avec les autres parce qu'elles ont des sélecteurs identiques. Deuxièmement, cela permet de réduire la taille des binaires en n'ayant pas à générer de thunks pour les membres qui n'ont pas besoin d'être exposés à Obj-C, et troisièmement, cela améliore la vitesse de l'enchaînement dynamique.
Si vous voulez exposer un membre à Obj-C, vous devez le marquer comme @objc
par exemple :
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self, action: #selector(foo), for: .touchUpInside)
}
@objc func foo() {
// ...
}
}
(le migrateur devrait le faire automatiquement pour vous avec les sélecteurs lorsqu'il fonctionne avec l'option "minimiser l'inférence")
Pour exposer un groupe de membres à Obj-C, vous pouvez utiliser un fichier @objc extension
:
@objc extension ViewController {
// both exposed to Obj-C
func foo() {}
func bar() {}
}
Cela exposera à Obj-C tous les membres qui y sont définis et provoquera une erreur pour tous les membres qui ne peuvent pas être exposés à Obj-C (à moins qu'ils ne soient explicitement marqués comme des @nonobjc
).
Si vous avez une classe pour laquelle vous avez besoin de todos pour que les membres compatibles avec Obj-C soient exposés à Obj-C, vous pouvez marquer la classe comme @objcMembers
:
@objcMembers
class ViewController: UIViewController {
// ...
}
Maintenant, tous les membres dont on peut déduire qu'ils sont @objc
sera. Cependant, je ne vous conseille pas de le faire si vous n'avez pas vraiment ont besoin que tous les membres soient exposés à Obj-C, compte tenu des inconvénients susmentionnés liés à l'exposition inutile de certains membres.
3 votes
Non, en les marquant comme
@objc
es sont désormais nécessaires pour les exposer à Obj-C, et donc les utiliser avec des sélecteurs.3 votes
La partie dépréciée consiste donc à déduire les fonctions d'accès public en tant que
@objc
? C'est un peu ennuyeux, mais je rends généralement ces fonctions privées, ce qui m'oblige à les marquer en tant que@objc
Quoi qu'il en soit.2 votes
Véase SE-0160 pour plus d'informations sur ce changement. Une autre solution consiste à marquer votre classe donnée comme
@objcMembers
afin d'exposer à Obj-C tous les membres compatibles avec Obj-C, mais je ne le conseillerais pas à moins que vous n'ayez réellement besoin que toute votre classe soit exposée.0 votes
Quelle en serait la conséquence, @Hamish ? Il semble plus pratique de mettre toute la classe à
@objc
que de le faire pour chaque fonction individuellement.3 votes
@LinusGeffarth Comme indiqué dans la proposition, cela augmenterait probablement inutilement la taille de votre binaire et la liaison dynamique prendrait plus de temps. Je ne pense vraiment pas que ce soit trop de tracas pour la clarté supplémentaire que vous voulez spécifiquement pour une chose particulière à utiliser à partir d'Obj-C.
0 votes
En résumé, la seule solution serait de marquer chaque fonction individuelle (qui l'exige) avec la mention
@objc
. Si c'est le cas, postez-le comme réponse et je l'accepterai. @Hamish. Merci pour votre aide !0 votes
Essayez ceci
#selector(ViewController.myAction)
1 votes
J'ai essayé, ça ne marche pas.
0 votes
Question connexe qui touche au cœur du problème : stackoverflow.com/questions/44379348/