J'ai un projet Swift où je veux attacher une méthode à un événement de tap UIButton. J'ai le code suivant:
class MyClass {
let myButton = UIButton(frame: CGRectMake(50, 50, 100, 50))
init() {
myButton.addTarget(self, #selector(self.didTap(_:)), forControlEvents: .TouchUpInside)
}
func didTap(sender: UIButton) {
print("Tapped")
}
}
XCode met en évidence ma ligne addTarget
et dit:
Argument of '#selector' refers to a method that is not exposed to Objective-C
Si j'ajoute le préfixe @objc
À mon func didTap
Comme il le suggère, alors tout fonctionne bien.
Dois-je activer quelque chose dans mes paramètres de construction qui provoque ce comportement étrange?
PS. J'obtiens ce comportement dans 7.3.1. Mais si j'essaye ceci dans 7.2.1 il n'accepte pas la syntaxe #selector(method(_:))
, et Selector("method:")
fonctionne très bien.
Les sélecteurs sont une fonctionnalité d'Objective-C et ne peuvent être utilisés qu'avec des méthodes exposées au runtime Obj-C dynamique. Vous ne pouvez pas avoir un sélecteur pour une méthode Swift pure.
Si votre classe hérite de NSObject
, ses méthodes publiques sont automatiquement exposées à Obj-C. Puisque votre classe n'hérite pas de NSObject
, vous devez utiliser l'attribut @objc
Pour indiquer que vous voulez que cette méthode soit exposée à Obj-C afin qu'elle puisse être appelée avec un sélecteur Obj-C.
#selector()
est la nouvelle syntaxe de Swift 2.2. Elle permet au compilateur de vérifier que le sélecteur que vous essayez d'utiliser existe réellement. L'ancienne syntaxe est obsolète et sera supprimé dans Swift 3.0.
Si j'ajoute le préfixe @objc à mon func
didTap
comme il le suggère, alors tout fonctionne bien.Dois-je activer quelque chose dans mes paramètres de construction qui provoque ce comportement étrange?
Non. Ce que vous voyez est normal. Les sélecteurs sont une fonctionnalité Objective-C, tout comme l'utilisation d'un sélecteur pour envoyer un message à votre instance de classe. La seule façon dont Objective-C peut envoyer ce message est s'il peut voir votre classe ou la méthode elle-même. MyClass n'est pas lui-même dérivé de NSObject, donc Objective-C ne peut pas le voir. Donc, si vous ne voulez pas le dériver de NSObject, vous devez au moins exposer la méthode à Objective-C en la marquant avec @objc
.
et Selector ("méthode:") fonctionne très bien
Dans les versions antérieures de Swift, le compilateur ne vous aiderait pas dans cette situation, donc votre code se compilerait. Mais vous auriez planté lorsque le message est arrivé et Objective-C n'a pas pu trouver la méthode. L'intérêt de la #selector
la syntaxe est pour vous aider à éviter ce plantage. Et c'est exactement ce qu'il a fait!