@selector () dans Swift?

J’essaie de créer un NSTimer dans Swift mais j’ai des problèmes.

 NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true) 

test() est une fonction de la même classe.


Je reçois une erreur dans l’éditeur:

Impossible de trouver une surcharge pour ‘init’ qui accepte les arguments fournis

Lorsque je change de selector: test() en selector: nil erreur ne 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.

    Swift luimê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 as tests / as place de respondsToSelector: et utilisez des fermetures partout où vous le pouvez au lieu de performSelector: pour une sécurité de type / mémoire améliorée.)

    Mais il existe encore un certain nombre d’API basées sur ObjC qui utilisent des sélecteurs, y compris des temporisateurs et le modèle cible / action. Swift fournit le type de Selector pour travailler avec ceux-ci. (Swift l’utilise automatiquement à la place du type SEL 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 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? Une référence de fonction est vérifiée par le compilateur Swift. Vous pouvez donc utiliser l’expression #selector 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 rendre votre référence de fonction aussi spécifique que nécessaire, conformément aux règles de Swift 2.2+ pour le nommage par type de fonction .

    (Il s’agit en fait d’une amélioration par rapport à la directive @selector() d’ @selector() , car le contrôle -Wundeclared-selector du compilateur vérifie uniquement l’existence du sélecteur nommé. La référence de fonction Swift que vous transmettez à #selector vérifie l’existence, l’appartenance à une classe et #selector signature .)

    Il y a quelques mises en garde supplémentaires pour les références de fonction que vous transmettez à l’expression #selector :

    • Plusieurs fonctions avec le même nom de base peuvent être différenciées par leurs étiquettes de parameters en utilisant la syntaxe susmentionnée pour les références de fonctions (par exemple, insertSubview(_:at:) vs insertSubview(_:aboveSubview:) ). Mais si une fonction n’a pas de parameters, la seule façon de le désambiguïser est d’utiliser un cast 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, avec un var foo: Int , vous pouvez utiliser #selector(getter: MyClass.foo) ou #selector(setter: MyClass.foo) .

    Notes générales:

    Cas où #selector ne fonctionne pas et dénomination: Parfois, vous n’avez pas de référence de fonction pour créer un sélecteur (par exemple, avec des méthodes enregistrées dynamicment dans l’environnement d’exécution 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 nommage 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 @objc atsortingbut @objc . (Dans les versions précédentes, vous avez cet atsortingbut gratuitement dans certains cas, mais vous devez maintenant le déclarer explicitement.)

    Rappelez-vous que private symboles private ne sont pas exposés au runtime également – votre méthode doit avoir au moins internal visibilité internal .

    Chemins clés: Ils sont liés aux sélecteurs, mais pas tout à fait les mêmes. Il existe également une syntaxe spéciale dans Swift 3: par exemple chris.valueForKeyPath(#keyPath(Person.friends.firstName)) . Voir SE-0062 pour plus de détails. Et encore plus de choses KeyPath dans Swift 4 , assurez-vous d’utiliser la bonne API basée sur KeyPath plutôt que des sélecteurs, le cas échéant.

    Vous pouvez en savoir plus sur les sélecteurs sous Interaction avec les API Objective-C dans Utilisation de Swift avec Cocoa et Objective-C .

    Remarque: Avant Swift 2.2, Selector était conforme à SsortingngLiteralConvertible , vous pourriez donc trouver un ancien code dans lequel les chaînes nues sont transmises aux API prenant des sélecteurs. Vous voudrez exécuter “Convertir en syntaxe Swift actuelle” dans Xcode pour obtenir ceux utilisant #selector .

    Voici un exemple rapide d’utilisation de 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 tant que chaîne ne fonctionne pas, elle échouera lors de l’exécution, et non lors de la compilation, et plantera votre application. Faites attention

    De plus, si votre classe (Swift) ne descend pas d’une classe Objective-C, vous devez avoir deux points à la fin de la chaîne de nom de la 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 “Unrecognized Selector” lors de l’exécution.

    Swift 2.2+ et Swift 3 Update

    Utilisez la nouvelle expression #selector , qui élimine le besoin d’utiliser des littéraux de chaîne pour rendre l’utilisation moins sujette aux erreurs. Pour référence:

     Selector("keyboardDidHide:") 

    devient

     #selector(keyboardDidHide(_:)) 

    Voir aussi: Proposition Swift Evolution

    Note (Swift 4.0):

    Si vous utilisez #selector vous devez marquer la fonction comme @objc

    Exemple:

    @objc func something(_ sender: UIButton)

    Pour les futurs lecteurs, j’ai constaté que j’ai rencontré un problème et que je recevais un unrecognised selector sent to instance erreur d’ unrecognised selector sent to instance provoquée par le marquage de la func cible comme étant privé.

    Le func DOIT être publiquement visible pour être appelé par un object avec une référence à un sélecteur.

    Juste au cas où quelqu’un d’autre aurait le même problème avec NSTimer, où aucune des autres réponses ne résout le problème, il est vraiment important de le mentionner si vous utilisez une classe qui n’hérite pas de NSObject directement ou en profondeur dans la hiérarchie ( Par exemple, des 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 rendre la classe héritée de NSObject, j’ai cessé de recevoir l’erreur “Unrecognized selector” et ma logique fonctionnait comme prévu.

    Swift 4.0

    vous créez le sélecteur comme ci-dessous.

    1.append l’événement à un bouton comme:

     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 depuis NSTimer, 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 theSsortingngToPrint = timer.userInfo as Ssortingng println(theSsortingngToPrint) } 

    Incluez les deux points dans le texte du sélecteur (testeur 🙂 et vos parameters vont dans userInfo.

    Votre fonction devrait prendre NSTimer comme paramètre. Ensuite, extrayez simplement userInfo pour obtenir le paramètre transmis.

    Les sélecteurs sont une représentation interne d’un nom de méthode dans Objective-C. Dans Objective-C, “@selector (methodName)” convertit une méthode de code source en un type de données SEL. Comme vous ne pouvez pas utiliser la syntaxe @selector dans Swift (le rickster y est placé), vous devez spécifier manuellement le nom de la méthode en tant qu’object Ssortingng ou en passant un object Ssortingng 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") ) 
     // 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 } 

    Swift 4.1
    Avec échantillon de geste

     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

     Create Refresh control using Selector method. var refreshCntrl : UIRefreshControl! refreshCntrl = UIRefreshControl() refreshCntrl.tintColor = UIColor.whiteColor() refreshCntrl.atsortingbutedTitle = NSAtsortingbutedSsortingng(ssortingng: "Please Wait...") refreshCntrl.addTarget(self, action:"refreshControlValueChanged", forControlEvents: UIControlEvents.ValueChanged) atableView.addSubview(refreshCntrl) 

    // Actualiser 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 targetAction 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") } } } 

    Lors de l’utilisation de performSelector()

    /addtarget()/NStimer.scheduledTimerWithInterval() méthodes votre méthode (correspondant au sélecteur) doit être marquée comme

     @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 ()” à la place du nom de la chaîne et du sélecteur afin que les possibilités d’erreur d’orthographe et de blocage ne le soient plus. Ci-dessous, 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 est remplacée par une simple chaîne nommant la méthode à appeler. Il y a un domaine où nous pouvons tous convenir que la verbosité a gêné. Bien sûr, si nous déclarons qu’il existe une méthode cible appelée flatButtonPressed: il est préférable d’en écrire une:

     func flatButtonPressed(sender: AnyObject) { NSLog("flatButtonPressed") } 

    régler la timer:

      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é que beaucoup de ces réponses étaient utiles, mais il n’était pas clair comment faire cela avec quelque chose qui n’était pas un bouton. J’étais en train d’append un logiciel de reconnaissance de gestes à un UILabel dans un environnement rapide et difficile. Voici ce que j’ai trouvé 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:

     func labelTapped(sender: UILabel) { } 

    Notez qu’il est public et que je n’utilise pas la syntaxe Selector () mais il est possible de le faire également.

     let tapRecognizer = UITapGestureRecognizer( target: self, action: Selector("labelTapped:")) 

    Utiliser #selector vérifiera votre code au moment de la compilation pour vous assurer que la méthode que vous souhaitez 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 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 les actions.

    Par exemple, j’ai constaté que lors de la configuration d’un UIBarButtonItem, je devais créer le bouton dans viewDidLoad, sinon je verrais une exception de sélecteur non reconnue.

     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") } 

    Changer comme une simple chaîne dans la méthode appelant la syntaxe du sélecteur

     var timer1 : NSTimer? = nil timer1= NSTimer(timeInterval: 0.1, target: self, selector: Selector("test"), userInfo: nil, repeats: true) 

    Ensuite, tapez 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 une timer

     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.