Swift lui - même n'utilise pas de sélecteurs - plusieurs modèles de conception qui dans Objective-C utilisent des sélecteurs fonctionnent différemment dans Swift. (Par exemple, utilisez le chaînage facultatif sur les types de protocole ou is/ astests au lieu de respondsToSelector:, et utilisez des fermetures partout où vous le pouvez performSelector:pour une meilleure sécurité de type / mémoire.)
Mais il existe encore un certain nombre d'API importantes basées sur ObjC qui utilisent des sélecteurs, y compris des minuteries et le modèle cible / action. Swift fournit le Selectortype pour travailler avec ces derniers. (Swift l'utilise automatiquement à la place du SELtype d'ObjC .)
Dans Swift 2.2 (Xcode 7.3) et versions ultérieures (y compris Swift 3 / Xcode 8 et Swift 4 / Xcode 9):
Vous pouvez construire un à Selectorpartir d'un type de fonction Swift à l'aide de l' #selectorexpression.
let timer = Timer(timeInterval: 1, target: object,
selector: #selector(MyClass.test),
userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
with: button, with: otherButton)
La grande chose à propos de cette approche? Une référence de fonction est vérifiée par le compilateur Swift, vous pouvez donc utiliser l' #selectorexpression uniquement avec des paires classe / méthode qui existent réellement et peuvent être utilisées comme sélecteurs (voir «Disponibilité du sélecteur» ci-dessous). Vous êtes également libre de faire votre référence de fonction uniquement aussi spécifique que vous le souhaitez, conformément aux règles Swift 2.2+ pour la dénomination de type de fonction .
(Il s'agit en fait d'une amélioration par rapport à la @selector()directive ObjC , car la -Wundeclared-selectorvérification du compilateur vérifie uniquement que le sélecteur nommé existe. La référence à la fonction Swift que vous passez pour #selectorvérifier l'existence, l'appartenance à une classe et la signature de type.)
Il y a quelques mises en garde supplémentaires pour les références de fonction que vous passez à l' #selectorexpression:
- Plusieurs fonctions avec le même nom de base peuvent être différenciées par leurs étiquettes de paramètres en utilisant la syntaxe susmentionnée pour les références de fonction (par exemple
insertSubview(_:at:)vs insertSubview(_:aboveSubview:)). Mais si une fonction n'a pas de paramètres, la seule façon de lever l'ambiguïté est d'utiliser un astranstypage avec la signature de type de la fonction (par exemple foo as () -> ()vs foo(_:)).
- Il existe une syntaxe spéciale pour les paires getter / setter de propriété dans Swift 3.0+. Par exemple, étant donné un
var foo: Int, vous pouvez utiliser #selector(getter: MyClass.foo)ou #selector(setter: MyClass.foo).
Notes générales:
Cas où #selectorcela ne fonctionne pas et dénomination: Parfois, vous n'avez pas de référence de fonction avec laquelle faire un sélecteur (par exemple, avec des méthodes enregistrées dynamiquement dans le runtime ObjC). Dans ce cas, vous pouvez construire un à Selectorpartir d'une chaîne: par exemple Selector("dynamicMethod:")- bien que vous perdiez la vérification de validité du compilateur. Lorsque vous faites cela, vous devez suivre les règles de dénomination ObjC, y compris les deux-points ( :) pour chaque paramètre.
Disponibilité du sélecteur: la méthode référencée par le sélecteur doit être exposée au runtime ObjC. Dans Swift 4, chaque méthode exposée à ObjC doit avoir sa déclaration précédée de l' @objcattribut. (Dans les versions précédentes, vous disposiez de cet attribut gratuitement dans certains cas, mais maintenant vous devez le déclarer explicitement.)
N'oubliez pas que les privatesymboles ne sont pas non plus exposés à l'exécution - votre méthode doit avoir au moins une internalvisibilité.
Chemins d'accès: ceux-ci sont liés mais pas tout à fait identiques aux sélecteurs. Il y a aussi une syntaxe spéciale pour ceux-ci dans Swift 3: par exemple chris.valueForKeyPath(#keyPath(Person.friends.firstName)). Voir SE-0062 pour plus de détails. Et encore plus de KeyPathchoses dans Swift 4 , alors assurez-vous d'utiliser la bonne API basée sur KeyPath au lieu de sélecteurs, le cas échéant.
Vous pouvez en savoir plus sur les sélecteurs sous Interagir avec les API Objective-C dans Utilisation de Swift avec Cocoa et Objective-C .
Remarque: Avant Swift 2.2, Selectorconforme à StringLiteralConvertible, vous pouvez donc trouver de l'ancien code où des chaînes nues sont passées aux API qui acceptent les sélecteurs. Vous aurez envie d'exécuter "Convertir en syntaxe Swift actuelle" dans Xcode pour obtenir ceux qui utilisent #selector.
selector: test()appelertestet passer sa valeur de retour à l'selectorargument.