Utiliser les sélecteurs en Swift

Pour ceux qui ne s'en rappelle plus les sélecteurs étaient des objets permettant de sélectionner une méthode pour une autre méthode afin qu'elle l'invoque dynamiquement durant son exécution.

[NSTimer scheduledTimerWithTimeInterval:2.0
    target:self
    selector:@selector(targetMethod:)
    userInfo:nil
    repeats:NO];

Le sélecteur que l'on passe en paramètre ici sélectionne une méthode s'appelant tergetMethod et prenant un paramètre.

Le sélecteur en Swift 1.0

Les sélecteurs existent aussi en swift. En swift 1.0 il suffisait de passer une chaîne de caractère du même format qu'en objective-C qui indiquait le nom de la méthode à sélectionner comme ci-dessous.

NSTimer.scheduledTimerWithTimeInterval(1, 
    target: self, 
    selector: "addOne:", 
    userInfo: nil, 
    repeats: true)

Le sélecteur en Swift 2.0

En Swift 2.0 il n'y a pas grand-chose qui change : le langage ne veut juste plus se contenter d'une chaîne de caractère.

On crée donc un objet de type Selector comme ci-dessous :

NSTimer.scheduledTimerWithTimeInterval(1, 
    target: self, 
    selector: Selector("addOne:"), 
    userInfo: nil, 
    repeats: true)

Tout aussi simple qu'avant donc ; il faut juste le savoir.

Notez qu'il est aussi possible d'utiliser une variable de type Selector et tous les avantages que cela implique pour accomplir le travail.

let timerSelector: Selector = Selector("addOne:")

NSTimer.scheduledTimerWithTimeInterval(1, 
    target: self, 
    selector: timerSelector, 
    userInfo: nil, 
    repeats: true)

Méthodes privées

Attention cependant aux méthodes privée. Le code ci-dessus ne fonctionnerait pas si la méthode addOne(_:) était marquée comme privée.

Selon la doc d'Apple, les méthodes privées ne sont pas montrées au runtime Objective-C. Vous aurez donc une erreur du type :

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[App.Controller addOne:]: unrecognized selector sent to instance XXX

Deux solutions s'offrent donc à vous :

  • Rendre votre méthode publique
  • Utiliser @objc devant la déclaration de votre méthode comme ceci : @objc private func addOne(_: Integer)

Les nouveautés de Swift 2.2

Comme pour Swift 2.0, les changements syntaxiques apporté par Swift 2.2 ne sont pas énorme. Jugez par vous-même :

NSTimer.scheduledTimerWithTimeInterval(1, 
    target: self, 
    selector: #selector(addOne:), 
    userInfo: nil, 
    repeats: true)

L'intérêt de ce changement ? Le sélecteur n'est plus qu'une simple string. Avec cette nouvelle syntaxe, le sélecteur est vérifié à la compilation : si la fonction sélectionnée n'existe pas une erreur est levé.

On évite ainsi des erreurs improbables. On gagne du temps de débogage et ça, c’est beau.

Pour aller plus loin :