Le correctif est correct - il n'y a rien dans le sélecteur que vous pouvez changer pour que la méthode à laquelle il se réfère soit exposée à Objective-C.
La raison de cet avertissement en premier lieu est le résultat du SE-0160 . Avant Swift 4, internal
ou les membres compatibles Objective-C ou supérieurs des NSObject
classes héritières étaient déduits comme étant @objc
et donc exposés à Objective-C, leur permettant ainsi d'être appelés à l'aide de sélecteurs (car le runtime Obj-C est nécessaire pour rechercher la méthode implémentation pour un sélecteur donné).
Cependant dans Swift 4, ce n'est plus le cas. Seules les déclarations très spécifiques sont désormais supposées être @objc
, par exemple, des substitutions de @objc
méthodes, des implémentations d' @objc
exigences de protocole et des déclarations avec des attributs qui impliquent @objc
, tels que @IBOutlet
.
La motivation derrière cela, comme détaillé dans la proposition liée ci-dessus , est tout d'abord d'éviter que les surcharges de méthodes lors de l' NSObject
héritage de classes ne se heurtent en raison de sélecteurs identiques. Deuxièmement, cela aide à réduire la taille binaire en n'ayant pas à générer des thunks pour les membres qui n'ont pas besoin d'être exposés à Obj-C, et troisièmement, améliore la vitesse de liaison dynamique.
Si vous souhaitez 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 programme de migration doit le faire automatiquement pour vous avec des sélecteurs lors de l'exécution avec l'option «minimiser l'inférence» sélectionnée)
Pour exposer un groupe de membres à Obj-C, vous pouvez utiliser un @objc extension
:
@objc extension ViewController {
// both exposed to Obj-C
func foo() {}
func bar() {}
}
Cela exposera tous les membres qui y sont définis à Obj-C, et donnera une erreur sur tous les membres qui ne peuvent pas être exposés à Obj-C (sauf s'ils sont explicitement marqués comme @nonobjc
).
Si vous avez une classe où vous avez besoin que tous les membres compatibles Obj-C soient exposés à Obj-C, vous pouvez marquer la classe comme @objcMembers
:
@objcMembers
class ViewController: UIViewController {
// ...
}
Maintenant, tous les membres qui peuvent être déduits le @objc
seront. Cependant, je ne conseillerais pas de faire cela à moins que vous n'ayez vraiment besoin de tous les membres exposés à Obj-C, étant donné les inconvénients mentionnés ci-dessus d'avoir des membres inutilement exposés.
@objc
est maintenant nécessaire pour les exposer à Obj-C, et donc les utiliser avec des sélecteurs.