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
/ as
tests 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 Selector
type pour travailler avec ces derniers. (Swift l'utilise automatiquement à la place du SEL
type 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 à Selector
partir d'un type de fonction Swift à l'aide de l' #selector
expression.
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' #selector
expression 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-selector
vérification du compilateur vérifie uniquement que le sélecteur nommé existe. La référence à la fonction Swift que vous passez pour #selector
vé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' #selector
expression:
- 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 as
transtypage 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ù #selector
cela 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 à Selector
partir 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' @objc
attribut. (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 private
symboles ne sont pas non plus exposés à l'exécution - votre méthode doit avoir au moins une internal
visibilité.
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 KeyPath
choses 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, Selector
conforme à 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()
appelertest
et passer sa valeur de retour à l'selector
argument.