web-dev-qa-db-fra.com

Swift veut que l'argument de #selector soit exposé à Objective-C

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.

25
Jason Woodland

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.

60
Darren

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!

12
matt