@selector () dans Swift?
j'essaie de créer un NSTimer
dans Swift
mais j'ai quelques problèmes.
NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)
test()
est une fonction de la même classe.
j'obtiens une erreur de l'éditeur:
N'a pas pu trouver de surcharge pour "init" qui accepte les arguments
quand je change selector: test()
en selector: nil
l'erreur disparaît.
j'ai essayé:
-
selector: test()
-
selector: test
-
selector: Selector(test())
mais rien ne fonctionne et je ne trouve pas de solution dans les références.
21 réponses
Swift lui - même n'utilise pas de sélecteurs-plusieurs modèles de conception qui dans L'objectif-c font usage de sélecteurs fonctionnent différemment dans Swift. (Par exemple , utilisez des chaînes optionnelles sur les types de protocole ou is
/ as
tests au lieu de respondsToSelector:
, et utilisez des fermetures partout où vous pouvez au lieu de performSelector:
pour une meilleure sécurité de type/mémoire.)
mais il existe encore un certain nombre d'API importantes basées sur L'ObjC qui utilisent des sélecteurs, y compris les minuteries et le schéma cible/action. Swift fournit le type Selector
pour travailler avec ceux-ci. (Swift utilise automatiquement cette option à la place du type SEL
D'ObjC.)
dans Swift 2.2 (Xcode 7.3) et les versions suivantes (y compris Swift 3 / Xcode 8 et Swift 4 / Xcode 9):
vous pouvez construire un Selector
à partir d'un type de fonction Swift en utilisant l'expression #selector
.
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? Un la référence de la fonction est vérifiée par le compilateur Swift, de sorte que vous pouvez utiliser l'expression #selector
seulement avec les paires de classes/méthodes qui existent réellement et qui sont éligibles pour une utilisation comme sélecteurs (voir "disponibilité du sélecteur" ci-dessous). Vous êtes également libre de rendre votre référence de fonction aussi spécifique que vous le souhaitez, comme dans les règles Swift 2.2+ Pour la désignation de type de fonction .
(il s'agit en fait d'une amélioration par rapport à la directive @selector()
de L'ObjC, parce que la le contrôle -Wundeclared-selector
du compilateur vérifie seulement que le sélecteur nommé existe. La référence de la fonction Swift que vous passez à #selector
vérifie l'existence, l'appartenance à une classe et le type de signature.)
il y a quelques mises en garde supplémentaires pour la fonction références que vous passez à l'expression #selector
:
- des fonctions multiples avec le même nom de base peuvent être différenciées par leurs étiquettes de paramètre en utilisant les susnommés syntaxe de la fonction des références (par exemple
insertSubview(_:at:)
vsinsertSubview(_:aboveSubview:)
). Mais si une fonction n'a pas de paramètres, la seule façon de désambiguer est d'utiliser unas
moulé avec la signature de type de la fonction (par exemplefoo as () -> ()
vsfoo(_:)
). - il y a une syntaxe spéciale pour les couples propriété getter/setter dans Swift 3.0+. Par exemple , avec un
var foo: Int
, vous pouvez utiliser#selector(getter: MyClass.foo)
ou#selector(setter: MyClass.foo)
.
remarques Générales:
cas où #selector
ne fonctionne pas, et appellation: parfois, vous n'avez pas de référence de fonction pour faire un sélecteur avec (par exemple, avec des méthodes dynamiquement enregistrées dans L'exécution ObjC). Dans ce cas, vous pouvez construire un Selector
à partir d'une chaîne de caractères: 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 nommage ObjC, y compris les colons ( :
) pour chaque paramètre.
disponibilité du sélecteur: la méthode référencée par le sélecteur doit être exposée à L'exécution ObjC. Dans Swift 4, chaque méthode exposée à ObjC doit avoir sa déclaration préfacée avec l'attribut @objc
. (Dans les versions précédentes, vous avez cet attribut gratuitement dans certains cas, mais maintenant vous devez le déclarer explicitement.)
rappelez - vous que les symboles private
ne sont pas exposés le moteur d'exécution, votre méthode doit avoir au moins internal
visibilité.
chemins de Clé: Ces sont liées, mais pas tout à fait les mêmes que les sélecteurs. Il y a une syntaxe spéciale pour ceux-ci dans Swift 3, aussi: par exemple chris.valueForKeyPath(#keyPath(Person.friends.firstName))
. Voir SE-0062 pour plus de détails. Et encore plus KeyPath
stuff in Swift 4 , alors assurez-vous que vous utilisez la bonne API basée sur le chemin de clavier au lieu de sélecteurs si approprié.
vous pouvez en savoir plus sur les sélecteurs sous interagissant avec L'objectif-c APIs dans utilisant Swift avec le cacao et L'objectif-c .
Note: avant Swift 2.2, Selector
conforme à StringLiteralConvertible
, de sorte que vous pourriez trouver un vieux code où des cordes nues sont passées aux API qui prennent des sélecteurs. Vous voulez lancer "Convert to Current Swift syntaxe" dans Xcode pour obtenir ceux qui utilisent #selector
.
voici un exemple rapide sur la façon d'utiliser la classe Selector
sur Swift:
override func viewDidLoad() {
super.viewDidLoad()
var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))
self.navigationItem.rightBarButtonItem = rightButton
}
func method() {
// Something cool here
}
notez que si la méthode passée en chaîne ne fonctionne pas, elle échouera à l'exécution, ne compilera pas le temps, et écrasera votre application.
aussi, si votre classe (Swift) ne descend pas D'une classe Objective-C, vous devez avoir un deux-points à la fin de la chaîne de noms de méthode cible et vous devez utiliser la propriété @objc avec votre méthode cible par exemple
var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))
@objc func method() {
// Something cool here
}
sinon vous obtiendrez une erreur de" sélecteur non reconnu " à l'exécution.
pour les futurs lecteurs, j'ai trouvé que j'avais un problème et que je recevais un unrecognised selector sent to instance
erreur causée par le fait que la cible func
a été marquée "private".
le func
doit être visible publiquement pour être appelé par un objet avec une référence à un sélecteur.
Swift 2.2+ et Swift 3 Mise à jour
utilisez la nouvelle expression #selector
, qui élimine la nécessité d'utiliser des chaînes de caractères littérales rendant l'utilisation moins sujette aux erreurs. Pour référence:
Selector("keyboardDidHide:")
devient
#selector(keyboardDidHide(_:))
Voir aussi: Swift Évolution Proposition
Note (Swift 4.0):
si vous utilisez #selector
vous devez marquer la fonction @objc
exemple:
@objc func something(_ sender: UIButton)
juste au cas où quelqu'un d'autre aurait le même problème que J'ai eu avec NSTimer où aucune des autres réponses n'a réglé le problème, il est vraiment important de mentionner que, si vous utilisez une classe qui n'hérite pas de NSObject directement ou profondément dans la hiérarchie(par exemple les fichiers swift créés manuellement), aucune des autres réponses ne fonctionnera même si elle est spécifiée comme suit:
let timer = NSTimer(timeInterval: 1, target: self, selector: "test",
userInfo: nil, repeats: false)
func test () {}
sans rien changer d'autre que de faire hériter la classe de NSObject j'ai arrêté d'avoir L'erreur" Unrecognized selector " et j'ai fait fonctionner ma logique comme prévu.
Swift 4.0
vous créez le sélecteur comme ci-dessous.
1.ajouter l'événement à un bouton:
button.addTarget(self, action: #selector(clickedButton(sender:)), for: UIControlEvents.touchUpInside)
et la fonction sera comme ci-dessous:
@objc func clickedButton(sender: AnyObject) {
}
si vous voulez passer un paramètre à la fonction du NSTimer alors voici votre solution:
var somethingToPass = "It worked"
let timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: "tester:", userInfo: somethingToPass, repeats: false)
func tester(timer: NSTimer)
{
let theStringToPrint = timer.userInfo as String
println(theStringToPrint)
}
inclue les deux points dans le texte du sélecteur (testeur:), et vos paramètres vont dans userInfo.
votre fonction devrait prendre NSTimer comme paramètre. Ensuite, il suffit d'extraire userInfo pour obtenir le paramètre passé.
sélecteurs sont une représentation interne d'un nom de méthode dans objectif-C. Dans objectif-c" @selector(methodName) " convertirait une méthode de code source en un type de données de SEL. Puisque vous ne pouvez pas utiliser la syntaxe @selector dans Swift (rickster est sur le point là), vous devez spécifier manuellement le nom de la méthode comme un objet String directement, ou en passant un objet String au type Selector. Voici un exemple:
var rightBarButton = UIBarButtonItem(
title: "Logout",
style: UIBarButtonItemStyle.Plain,
target: self,
action:"logout"
)
ou
var rightBarButton = UIBarButtonItem(
title: "Logout",
style: UIBarButtonItemStyle.Plain,
target: self,
action:Selector("logout")
)
Swift 4.1
avec échantillon de geste du robinet
let gestureRecognizer = UITapGestureRecognizer()
self.view.addGestureRecognizer(gestureRecognizer)
gestureRecognizer.addTarget(self, action: #selector(self.dismiss(completion:)))
// Use destination 'Class Name' directly, if you selector (function) is not in same class.
//gestureRecognizer.addTarget(self, action: #selector(DestinationClass.dismiss(completion:)))
@objc func dismiss(completion: (() -> Void)?) {
self.dismiss(animated: true, completion: completion)
}
voir le document D'Apple pour plus de détails sur: Selector Expression
// for swift 2.2
// version 1
buttton.addTarget(self, action: #selector(ViewController.tappedButton), forControlEvents: .TouchUpInside)
buttton.addTarget(self, action: #selector(ViewController.tappedButton2(_:)), forControlEvents: .TouchUpInside)
// version 2
buttton.addTarget(self, action: #selector(self.tappedButton), forControlEvents: .TouchUpInside)
buttton.addTarget(self, action: #selector(self.tappedButton2(_:)), forControlEvents: .TouchUpInside)
// version 3
buttton.addTarget(self, action: #selector(tappedButton), forControlEvents: .TouchUpInside)
buttton.addTarget(self, action: #selector(tappedButton2(_:)), forControlEvents: .TouchUpInside)
func tappedButton() {
print("tapped")
}
func tappedButton2(sender: UIButton) {
print("tapped 2")
}
// swift 3.x
button.addTarget(self, action: #selector(tappedButton(_:)), for: .touchUpInside)
func tappedButton(_ sender: UIButton) {
// tapped
}
button.addTarget(self, action: #selector(tappedButton(_:_:)), for: .touchUpInside)
func tappedButton(_ sender: UIButton, _ event: UIEvent) {
// tapped
}
Create Refresh control using Selector method.
var refreshCntrl : UIRefreshControl!
refreshCntrl = UIRefreshControl()
refreshCntrl.tintColor = UIColor.whiteColor()
refreshCntrl.attributedTitle = NSAttributedString(string: "Please Wait...")
refreshCntrl.addTarget(self, action:"refreshControlValueChanged", forControlEvents: UIControlEvents.ValueChanged)
atableView.addSubview(refreshCntrl)
//Actualisation De La Méthode De Contrôle
func refreshControlValueChanged(){
atableView.reloadData()
refreshCntrl.endRefreshing()
}
depuis la publication de Swift 3.0, il est même un peu plus subtil de déclarer une action cible appropriée
class MyCustomView : UIView {
func addTapGestureRecognizer() {
// the "_" is important
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(MyCustomView.handleTapGesture(_:)))
tapGestureRecognizer.numberOfTapsRequired = 1
addGestureRecognizer(tapGestureRecognizer)
}
// since Swift 3.0 this "_" in the method implementation is very important to
// let the selector understand the targetAction
func handleTapGesture(_ tapGesture : UITapGestureRecognizer) {
if tapGesture.state == .ended {
print("TapGesture detected")
}
}
}
Lorsqu'on utilise performSelector()
/addtarget()/NStimer.scheduledTimerWithInterval()
Méthodes votre méthode (correspondant au sélecteur) doit porter la mention
@objc
For Swift 2.0:
{
//...
self.performSelector(“performMethod”, withObject: nil , afterDelay: 0.5)
//...
//...
btnHome.addTarget(self, action: “buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
//...
//...
NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector : “timerMethod”, userInfo: nil, repeats: false)
//...
}
@objc private func performMethod() {
…
}
@objc private func buttonPressed(sender:UIButton){
….
}
@objc private func timerMethod () {
….
}
Pour Swift 2.2, vous devez écrire '# selector () ' au lieu du nom de la chaîne et du sélecteur pour que les possibilités d'erreurs d'orthographe et de plantage dues à cela ne soient plus là. Voici l'exemple
self.performSelector(#selector(MyClass.performMethod), withObject: nil , afterDelay: 0.5)
vous créez le sélecteur comme ci-dessous.
1.
UIBarButtonItem(
title: "Some Title",
style: UIBarButtonItemStyle.Done,
target: self,
action: "flatButtonPressed"
)
2.
flatButton.addTarget(self, action: "flatButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
notez que la syntaxe @selector a disparu et a été remplacée par une chaîne simple nommant la méthode à appeler. Il y a un domaine où nous pouvons tous convenir que la verbosité a entravé le chemin. Bien sûr, si nous avons déclaré qu'il y a une méthode cible appelée flatButtonPressed: nous ferions mieux d'en écrire une:
func flatButtonPressed(sender: AnyObject) {
NSLog("flatButtonPressed")
}
régler la minuterie:
var timer = NSTimer.scheduledTimerWithTimeInterval(1.0,
target: self,
selector: Selector("flatButtonPressed"),
userInfo: userInfo,
repeats: true)
let mainLoop = NSRunLoop.mainRunLoop() //1
mainLoop.addTimer(timer, forMode: NSDefaultRunLoopMode) //2 this two line is optinal
pour être complet, voici le flatButtonPressed
func flatButtonPressed(timer: NSTimer) {
}
j'ai trouvé bon nombre de ces réponses utiles, mais il n'était pas clair comment le faire avec quelque chose qui n'était pas un bouton. J'ajoutais un reconnaisseur de gestes à un UILabel de swift et j'ai lutté, alors voici ce que j'ai trouvé qui a fonctionné pour moi après avoir lu tout ce qui précède:
let tapRecognizer = UITapGestureRecognizer(
target: self,
action: "labelTapped:")
où le" sélecteur "a été déclaré comme suit:
func labelTapped(sender: UILabel) { }
notez que c'est public et que je n'utilise pas la syntaxe Selector() mais il est possible de le faire aussi.
let tapRecognizer = UITapGestureRecognizer(
target: self,
action: Selector("labelTapped:"))
en utilisant # selector vérifiera votre code au moment de la compilation pour s'assurer que la méthode que vous voulez appeler existe réellement. Encore mieux, si la méthode n'existe pas, vous obtiendrez une erreur de compilation: Xcode refusera de construire votre application, bannissant ainsi d'oublier une autre source possible de bogues.
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem =
UIBarButtonItem(barButtonSystemItem: .Add, target: self,
action: #selector(addNewFireflyRefernce))
}
func addNewFireflyReference() {
gratuitousReferences.append("Curse your sudden but inevitable betrayal!")
}
Il peut être utile de noter où vous configurez le contrôle qui déclenche l'action de questions.
par exemple, j'ai trouvé que lors de la mise en place d'un UIBarButtonItem, je devais créer le bouton dans viewDidLoad sinon j'obtiendrais une exception de sélecteur non reconnu.
override func viewDidLoad() {
super.viewDidLoad()
// add button
let addButton = UIBarButtonItem(image: UIImage(named: "746-plus-circle.png"), style: UIBarButtonItemStyle.Plain, target: self, action: Selector("addAction:"))
self.navigationItem.rightBarButtonItem = addButton
}
func addAction(send: AnyObject?) {
NSLog("addAction")
}
Changement comme une simple chaîne de nommage dans l'appel de méthode pour sélecteur de syntaxe
var timer1 : NSTimer? = nil
timer1= NSTimer(timeInterval: 0.1, target: self, selector: Selector("test"), userInfo: nil, repeats: true)
après cela, type func test ().
pour swift 3
let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.test), userInfo: nil, repeats: true)
Déclaration De Fonction Dans La Même Classe
func test()
{
// my function
}
Pour Swift 3
//Exemple de code pour créer de la minuterie
Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true)
WHERE
timeInterval:- Interval in which timer should fire like 1s, 10s, 100s etc. [Its value is in secs]
target:- function which pointed to class. So here I am pointing to current class.
selector:- function that will execute when timer fires.
func updateTimer(){
//Implemetation
}
repeats:- true/false specifies that timer should call again n again.