J'essaie de créer un NSTimer
in 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 passe selector: test()
à 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.
selector: test()
appelertest
et passer sa valeur de retour à l'selector
argument.Réponses:
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 derespondsToSelector:
, et utilisez des fermetures partout où vous le pouvezperformSelector:
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 duSEL
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.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:insertSubview(_:at:)
vsinsertSubview(_:aboveSubview:)
). Mais si une fonction n'a pas de paramètres, la seule façon de lever l'ambiguïté est d'utiliser unas
transtypage avec la signature de type de la fonction (par exemplefoo as () -> ()
vsfoo(_:)
).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 exempleSelector("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 uneinternal
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 deKeyPath
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
.la source
size:andShape:
si le premier argument est nommé, vous aurez peut-être besoin d'unWith
, c'est-initWithData:
à- dire pourfunc init(Data data: NSData)
Voici un exemple rapide sur la façon d'utiliser la
Selector
classe sur Swift:Notez que si la méthode passée sous forme de chaîne ne fonctionne pas, elle échouera lors de l'exécution, pas lors de la compilation, et plantera votre application. Faites attention
la source
@selector
c'est pratique, mais il n'est pas appliqué aussi formellement que vous pourriez le penser. Le "sélecteur non déclaré" n'est qu'un avertissement du compilateur, car de nouveaux sélecteurs peuvent toujours être introduits au moment de l'exécution. Cependant, les références de sélecteurs vérifiables / refactorisables dans Swift seraient une bonne demande de fonctionnalité .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
sinon, vous obtiendrez une erreur «Sélecteur non reconnu» lors de l'exécution.
la source
Selector
mot clé n'est pas obligatoire. Donc, dans ce cas, la signature doit être@objc func method(timer: NSTimer) {/*code*/}
@objc
travaillé pour moi. Je n'avais pas besoin d'incluretimer: NSTimer
dans ma signature de méthode pour qu'elle soit appelée.Mise à jour Swift 2.2+ et Swift 3
Utilisez la nouvelle
#selector
expression, ce qui élimine le besoin d'utiliser des littéraux de chaîne rendant l'utilisation moins sujette aux erreurs. Pour référence:devient
Voir aussi: Proposition Swift Evolution
Remarque (Swift 4.0):
Si
#selector
vous utilisez, vous devrez marquer la fonction comme@objc
Exemple:
@objc func something(_ sender: UIButton)
la source
Swift 4.0
vous créez le sélecteur comme ci-dessous.
1. ajoutez l'événement à un bouton comme:
et la fonction sera comme ci-dessous:
la source
@objc
avantfunc
ce qui est requis dans Swift 4.Pour les futurs lecteurs, j'ai constaté que j'avais rencontré un problème et que j'obtenais une
unrecognised selector sent to instance
erreur causée par le marquage de la ciblefunc
comme privée.Le
func
DOIT être publiquement visible pour être appelé par un objet avec une référence à un sélecteur.la source
objc
avant la déclaration de lui. Ex:@objc private func foo() { ...
alors vous pouvez utiliser"foo"
autant de sélecteurs que vous le souhaitezinternal
, ne spécifiant ainsi aucun modificateur d'accès. J'utilise souvent ce modèle://MARK: - Selector Methods\n extension MyController {\n func buttonPressed(_ button: 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ésolu 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 des fichiers swift créés manuellement), aucune des autres réponses ne fonctionnera même si est spécifié comme suit:
Sans rien changer d'autre que de simplement faire hériter la classe de NSObject, j'ai cessé d'obtenir l'erreur "sélecteur non reconnu" et j'ai fait fonctionner ma logique comme prévu.
la source
Si vous souhaitez passer un paramètre à la fonction à partir du NSTimer, voici votre solution:
Incluez les deux-points dans le texte du sélecteur (testeur :) et vos paramètres vont dans userInfo.
Votre fonction doit prendre NSTimer comme paramètre. Il suffit ensuite d'extraire userInfo pour obtenir le paramètre transmis.
la source
scheduledTimerWith...
l'ajoute automatiquement à la boucle d'exécution actuelle - donc il n'y a aucun comportement étrange ici du tout;)Les sélecteurs sont une représentation interne d'un nom de méthode dans Objective-C. Dans 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 (rickster est là), vous devez spécifier manuellement le nom de la méthode en tant qu'objet String directement, ou en passant un objet String au type Selector. Voici un exemple:
ou
la source
Swift 4.1
Avec un échantillon du geste du robinet
Voir le document d'Apple pour plus de détails sur: Expression du sélecteur
la source
la source
// Actualiser la méthode de contrôle
la source
Depuis la publication de Swift 3.0, il est même un peu plus subtil de déclarer une action cible appropriée
la source
Lors de l'utilisation
performSelector()
/addtarget()/NStimer.scheduledTimerWithInterval()
méthodes votre méthode (correspondant au sélecteur) doit être marquée commePour Swift 2.2, vous devez écrire '#selector ()' au lieu de la chaîne et du nom du sélecteur afin que les possibilités d'erreur d'orthographe et de plantage à cause de cela ne soient plus là. Voici un exemple
la source
vous créez le sélecteur comme ci-dessous.
1.
2.
Notez que la syntaxe @selector a disparu et a été 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é s'est mise en travers. Bien sûr, si nous déclarons qu'il existe une méthode cible appelée flatButtonPressed: il vaut mieux en écrire une:
régler la minuterie:
Pour être complet, voici le flatButtonPressed
la source
J'ai trouvé bon nombre de ces réponses utiles, mais il n'était pas clair comment procéder avec quelque chose qui n'était pas un bouton. J'étais en train d'ajouter un reconnaisseur de gestes à un UILabel rapidement et j'ai eu du mal alors voici ce que j'ai trouvé qui fonctionnait pour moi après avoir lu tout ce qui précède:
Où le "sélecteur" a été déclaré:
Notez qu'il est public et que je n'utilise pas la syntaxe Selector () mais il est également possible de le faire.
la source
L'utilisation de #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 de l'oubli une autre source possible de bugs.
la source
Il peut être utile de noter où vous configurez le contrôle qui déclenche 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.
la source
selector
est un mot duObjective-C
monde et vous pouvez l'utiliserSwift
pour avoir la possibilité d'appelerObjective-C
depuisSwift
Il vous permet d'exécuter du code à l'exécutionAvant
Swift 2.2
la syntaxe est:Étant donné que le nom de la fonction est passée en
Selector
tant queString
paramètre ( « foo ») , il est impossible de vérifier un nom dans la compilation . En conséquence, vous pouvez obtenir une erreur d'exécution:Après
Swift 2.2+
la syntaxe:La saisie semi-automatique de Xcode vous aide à appeler une bonne méthode
la source
Modifier comme une simple dénomination de chaîne dans la méthode appelant la syntaxe du sélecteur
Après cela, tapez func test ().
la source
Pour Swift 3
// Exemple de code pour créer une minuterie
la source
Sélecteur dans Swift 4:
la source
Pour swift 3
Déclaration de fonction Dans la même classe:
la source
self
sélecteur. Cela devrait suffire:let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(test), userInfo: nil, repeats: true)