Nouveau sucre syntaxique pour les Selector en Swift 2.2

La sortie officielle de Swift 2.2 il y a quelques jours nous a apporté son lot de nouveauté et d’amélioration dont celui que nous allons traiter aujourd’hui : la manipulation des sélecteurs (selector en anglais).

Avant l’arrivé de Swift 2.2 les sélecteurs étaient simplement des littéraux de chaîne et donc sujette aux erreurs car, étant des humains, nous n’étions pas à l’abris des fautes de frappe. Voici un example en Swift 2.1 et avant :

lazy var sendButton: UIButton = {
  let button = UIButton(type: .System)
  button.addTarget(self, action: "sendAction:", forControlEvents: .TouchUpInside)

  return button
}() 

func sendAction(sender: UIButton) {
  // ...
}

Pour éviter les problèmes et simplifier l’écriture du code, il est toujours bon de respecter une convention de nommage. Pour les actions et les sélecteurs nous utilisons (à titre personnel) le nom de l’action suivi du mot « Action » afin de comprendre rapidement le role de la méthode. Ici le nom donné à la méthode est sendAction qui possède un paramètre sender de type UIButton. Il est préférable de bien spécifier l’envoyeur avec le bon type car il vaut mieux l’avoir quand on en a pas besoin que de ne pas l’avoir quand on en a besoin.

Les sélecteurs en Swift 2.2

Afin de palier les éventuelles erreurs dues aux littéraux de chaîne , Swift 2.2 a introduit un nouveau sucre syntaxique appelé #selector(). Voici le même example que le précédent en Swift 2.2 :

class MyViewController: UIViewController {
  lazy var sendButton: UIButton = {
    let button = UIButton(type: .System)
    button.addTarget(self, action: #selector(MyViewController.sendAction(_:)), forControlEvents: .TouchUpInside)

    return button
  }() 

  func sendAction(sender: UIButton) {
    // ...
  }
}

Il faut avouer que cette syntaxe n’est pas des plus esthétiques. Néanmoins elle a le mérite d’évité les erreurs en profitant de l’auto-complétion fournit par Xcode (ou tout autre IDE). Donc ici le sélecteur #selector(MyViewController.sendAction(_:)) définit simplement la classe (MyViewController) et la méthode (sendAction(_:)) de la classe à appeler.

Heureusement on peut aussi profiter de l’utilisation de constante globale pour rendre notre code un peu plus lisible et maintenable :

struct Action {
  static let send = #selector(MyViewController.sendAction(_:))
}

lazy var sendButton: UIButton = {
  let button = UIButton(type: .System)
  button.addTarget(self, action: Action.send, forControlEvents: .TouchUpInside)

  return button
}() 

Génial, maintenant on a regroupé en un seul endroit l’ensemble des sélecteurs de notre objet ! Ainsi dès que l’on a besoin d’un sélecteur il suffit de faire appel à la structure Action. Il faut tout de même bien respecter une certaine convention de nommage afin de garder cette structure simple à maintenir.

Cependant nous pouvons encore faire mieux en étendant le type Selector. Voici l’example équivalent :

private extension Selector {
  static let sendAction = #selector(MyViewController.sendAction(_:))
}

lazy var sendButton: UIButton = {
  let button = UIButton(type: .System)
  button.addTarget(self, action: .sendAction, forControlEvents: .TouchUpInside)

  return button
}()

Pas mal, non ? Dans cet example nous avons étendu le type Selector pour lui ajouter un sélecteur statique qui pointe vers notre méthode. Cela nous permet de profiter de l’inférence de type de Swift afin d’utiliser directement le sélecteur en omettant d’utiliser le préfixe Selector quand on passe la valeur. C’est exactement la même chose que lorsque l’on omet le préfixe UIColor pour définir une couleur à une vue par example :

view.backgroundColor = .redColor()

L’extension est privé pour éviter de « polluer » l’ensemble du projet avec ces sélecteurs. Mais comme expliqué dans ce tutoriel, nous pouvons définir une extension publique avec des structures imbriquées :

extension Selector {
  struct MyViewController {
    static let sendAction = #selector(MyViewController.sendAction(_:))
  }
}

button.addTarget(self, action: Selector.MyViewController.sendAction, forControlEvents: .TouchUpInside)

Le problème avec cette solution c’est qu’on ne peut pas se passer du préfixe Selector sinon l’expression est trop ambiguë pour le compilateur.

Conclusion

Nous espérons que ce tutoriel vous a permit de mieux comprendre la nouvelle syntaxe des sélecteurs et vous aidera par la même occasion à mieux architecturer votre code. Si vous avez des commentaires, suggestions, améliorations ou autres n’hésitez pas à laisser un commentaire.

1 Etoile2 Etoiles3 Etoiles4 Etoiles5 Etoiles (2 votes, average: 5,00 out of 5)
Loading...

Aucun commentaire

Time limit is exhausted. Please reload CAPTCHA.

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.