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 remplace selector: test()
par 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.
Swift lui-même n'utilise pas de sélecteurs. Plusieurs modèles de conception qui, dans Objective-C, utilisent les sélecteurs de manière différente dans Swift. (Par exemple, utilisez un chaînage facultatif sur les types de protocole ou les tests is
/as
au lieu de respondsToSelector:
, et utilisez des fermetures chaque fois que vous le pouvez au lieu de performSelector:
pour améliorer la sécurité de type/mémoire. .)
Cependant, il existe encore un certain nombre d'API importantes basées sur ObjC qui utilisent des sélecteurs, notamment des minuteries et le modèle cible/action. Swift fournit le type Selector
pour travailler avec ceux-ci. (Swift l'utilise automatiquement à la place du type SEL
d'ObjC.)
Vous pouvez construire une Selector
à partir d'un type de fonction Swift à l'aide de 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 existantes et pouvant ê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 à le Swift 2.2+ règles de dénomination du type de fonction .
(Il s'agit en réalité d'une amélioration par rapport à la directive @selector()
de ObjC, car la vérification -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 dans une classe et tapez signature.)
Il y a quelques mises en garde supplémentaires pour les références de fonction que vous transmettez à l'expression #selector
:
insertSubview(_:at:)
vs insertSubview(_:aboveSubview:)
). Mais si une fonction n'a pas de paramètre, le seul moyen de la lever de toute ambiguïté consiste à utiliser un transtypage as
avec la signature de type de la fonction (par exemple, foo as () -> ()
vs foo(_:)
).var foo: Int
, vous pouvez utiliser #selector(getter: MyClass.foo)
ou #selector(setter: MyClass.foo)
. Cas où #selector
ne fonctionne pas et désignation: Parfois, vous ne disposez pas d'une référence de fonction pour créer 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. Pour ce faire, vous devez suivre les règles de dénomination ObjC, notamment 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 moteur d'exécution ObjC. Dans Swift 4, chaque déclaration de méthode exposée à ObjC doit être précédée de l'attribut @objc
. (Dans les versions précédentes, vous aviez cet attribut gratuitement dans certains cas, mais vous devez maintenant le déclarer explicitement.)
N'oubliez pas que les symboles private
ne sont pas exposés au runtime également - votre méthode doit avoir au moins la visibilité internal
.
Chemins d'accès aux clés: Ils sont liés aux sélecteurs, mais pas tout à fait. Il existe également une syntaxe spéciale pour ces éléments dans Swift 3: par exemple. chris.valueForKeyPath(#keyPath(Person.friends.firstName))
. Voir SE-0062 pour plus de détails. Et encore plus KeyPath
dans Swift 4 , assurez-vous donc que vous utilisez la bonne API basée sur KeyPath au lieu 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
conforme à StringLiteralConvertible
, vous pourrez donc trouver l'ancien code où Les chaînes nues sont transmises aux API qui acceptent les sélecteurs. Vous voudrez exécuter "Syntaxe en Swift courant" 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 transmise en tant que chaîne ne fonctionne pas, elle échouera au moment de l'exécution, pas à 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 un signe deux-points à la fin de la chaîne du 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" au moment de l'exécution.
Swift 2.2+ et Swift 3 Mise à jour
Utilisez la nouvelle expression #selector
, ce qui élimine la nécessité d'utiliser des littéraux de chaîne, ce qui rend l'utilisation moins sujette aux erreurs. Pour référence:
Selector("keyboardDidHide:")
devient
#selector(keyboardDidHide(_:))
Voir aussi: Proposition d'évolution rapide
Remarque (Swift 4.0):
Si vous utilisez #selector
vous devrez marquer la fonction comme @objc
Exemple:
@objc func something(_ sender: UIButton)
Pour les futurs lecteurs, j’ai constaté que j’avais un problème et que j’avais une erreur unrecognised selector sent to instance
provoquée par marquant la cible func
comme privée.
La func
DOIT être visible publiquement pour être appelée par un objet avec une référence à un sélecteur.
Swift 4.
vous créez le sélecteur comme ci-dessous.
1.ajouter 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) {
}
Juste au cas où quelqu'un d'autre aurait le même problème que NSTimer où aucune des autres réponses ne corrige 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, 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 simplement faire en sorte que la classe hérite de NSObject, j'ai cessé de recevoir l'erreur "Unrecognized selector" et ma logique a fonctionné comme prévu.
Si vous souhaitez transmettre un paramètre à la fonction à partir de 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 theStringToPrint = timer.userInfo as String
println(theStringToPrint)
}
Incluez les deux points dans le texte du sélecteur (testeur :), et vos paramètres vont dans userInfo.
Votre fonction devrait prendre NSTimer en paramètre. Ensuite, extrayez simplement userInfo pour obtenir le paramètre qui a été transmis.
Les sélecteurs sont une représentation interne d'un nom de méthode dans Objective-C. En Objective-C, "@selector (methodName)" convertirait une méthode de code source en un type de données SEL. Étant donné que vous ne pouvez pas utiliser la syntaxe @selector dans Swift (le rickster y est pointé), vous devez spécifier manuellement le nom de la méthode en tant qu'objet String 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 un échantillon de geste de tapotement
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)
// Actualiser la méthode de contrôle
func refreshControlValueChanged(){
atableView.reloadData()
refreshCntrl.endRefreshing()
}
Puisque Swift 3.0 est publié, il est même un peu plus subtil de déclarer une 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")
}
}
}
Lorsque vous utilisez 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 de la chaîne et du nom du sélecteur afin que les possibilités d'erreur d'orthographe et de plantage dus à cette erreur n'existent plus. Voici un exemple
self.performSelector(#selector(MyClass.performMethod), withObject: nil , afterDelay: 0.5)
Utiliser # selector vérifiera votre code lors de la compilation pour vous assurer que la méthode que vous souhaitez appeler existe réellement. Mieux encore, si la méthode n’existe pas, vous obtiendrez une erreur de compilation: Xcode refusera de créer 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!")
}
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'ajoutais un identificateur de geste à un UILabel dans Swift et je me suis débattu. Voici donc ce que j'ai trouvé qui a fonctionné pour moi après avoir tout lu ci-dessus:
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 aussi.
let tapRecognizer = UITapGestureRecognizer(
target: self,
action: Selector("labelTapped:"))
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 été remplacée par une simple chaîne nommant la méthode à appeler. Il ya un domaine dans lequel nous pouvons tous convenir que la verbosité est un obstacle. Bien sûr, si nous déclarons qu'il existe une méthode cible appelée flatButtonPressed: nous ferions mieux d'en écrire une:
func flatButtonPressed(sender: AnyObject) {
NSLog("flatButtonPressed")
}
régler le minuteur:
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) {
}
Il peut être utile de noter où vous configurez le contrôle qui déclenche l’importance de l’action.
Par exemple, j'ai constaté que lors de la configuration d'un UIBarButtonItem, je devais créer le bouton dans viewDidLoad, sinon j'obtiendrais 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 de nommage dans la méthode appelant syntaxe de sélecteur
var timer1 : NSTimer? = nil
timer1= NSTimer(timeInterval: 0.1, target: self, selector: Selector("test"), userInfo: nil, repeats: true)
Après cela, tapez func test ().
Sélecteur dans Swift 4:
button.addTarget(self, action: #selector(buttonTapped(sender:)), for: UIControlEvents.touchUpInside)
Pour Swift
// Exemple de code pour créer un 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.
Pour Swift
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:
@objc func test()
{
// my function
}