[iOS] Comment coupler les delegates et les closures ?

Introduction

Thibaud Huchon
Eleven Labs
Published in
4 min readJan 25, 2017

--

Salut les Astronautes, aujourd’hui on va continuer dans notre lancée sur le mobile, toujours en NATIF.

Cet article s’inscrit dans la lignée des 2 précédents, et il est impératif de les avoir lu pour comprendre ce dont il s’agit ici :

http://blog.eleven-labs.com/fr/delegates-closures/
http://blog.eleven-labs.com/fr/android-listeners/

Si vous avez lu les 2 précédents articles, vous devez vous douter de ce dont celui-ci va parler.
-Mais oui on sait, allez dépêche-toi là, on veut savoir comment faire un truc aussi sexy que les listeners mais sur iOS cette fois-ci.
-Ok, juste encore un petit peu de blabla technique et on se lance.

Comment ça va se passer :

Bon comme le premier article, pour que tout le monde soit heureux, je vais vous produire du DUMMY code en Objective-C comme en Swift.

Dans le monde du développement iOS, comme vous avez pu le comprendre, on peut utiliser les delegates ou bien les closures. En général, on va utiliser la closure pour plus de flexibilité et c’est aussi plus simple à mettre en place. Cependant, dans certains cas, des composants graphiques par exemple sont juste utilisables via un delegate ou un datasource. Je pense à 2 de ces composants que j’utilise beaucoup: UITableView et UICollectionView.

Sur ces 2 composants par exemple, pas possible d’utiliser de blocks/closures, et on doit passer par un bon delegate à l’ancienne. Dans l’absolu, ce n’est pas très gênant, sauf dans le cas où on se retrouve avec plusieurs de ces composants sur le même écran. Les méthodes deviennent alors énormes et cela devient compliqué de faire du code élégant. Ce que je vous propose ici est une petite solution que je trouve assez propre.

Mise en situation

Comme dans les deux articles précédents, on va juste faire un Appel GET sur une URL donnée et avoir un système qui nous prévient en cas de succès comme d’erreur. On va aller un peu plus vite que dans le premier article, car ce sont des notions que vous devez déjà maîtriser.

C’est parti pour le code !

Notre but ici est de réaliser une classe qui fait un GET sur une URL donnée. Je veux prévenir l’objet qui a été l’instigateur de cette requête si elle a réussi ou non. Pour éviter un couplage fort, on va utiliser le principe du delegate, grâce à ça, je n’aurai pas à connaitre le type exact de cet objet.

On va agir en 3 étapes:

-Créer un protocol
-Créer des blocks/closure
-Créer une classe qui hérite du protocole et qui a nos 2 blocks/closures en variables.

-Objective-C

On va maintenant implémenter la classe qui va hériter du protocole. Elle va donc contenir les 2 méthodes onRequestSuccess et onRequestFailure et chacune appellera le block/closure qui lui correspondra.

Ensuite, on code la classe RequestManager que vous devez commencer à connaître

Puis on va faire une méthode pour appeler notre webservice

On va un peu regarder ensemble ce que l’on a codé.
- On a instancié notre Manager, qui va appeler le webservice
- On a définit nos deux blocks/closures
- On a instancié notre Delegate
- On a assigné nos deux blocks/closures
- On a assigné le Delegate au Manager
- On appelle le webservice

Je vous donne le code Swift pour les plus impatients

- Swift

Si maintenant j’appelle la méthode callWebService, vu le dummy code que l’on a fait, le résultat sera un passage dans le block/closure requestSuccess.

Mais pourquoi faire tout ça ?

En effet, pourquoi faire tout ça, alors que dans notre cas, on pouvait juste utiliser un Delegate ou des blocks/closures comme dans le premier article ? Cela complexifie le code, et on a l’impression de faire les choses deux fois…
Comme je vous l’ai dit au début de l’article, cette solution vient pour un besoin assez spécifique. Celui de rendre un Delegate plus flexible quand on est obligé de passer par ce pattern.

Problèmes soulevés

-Si le Protocol contient beaucoup de méthodes, on en a beaucoup à ré-implémenter.
-On doit aussi définir tous les blocks/closures correspondants.
-Il faut redéfinir les blocks/closures pour chaque appel.

Gains apportés

-Des delegates plus flexibles
-Du code localisé
-Des méthodes réduites
-Une gestion plus fine des retours du Delegate

Cette solution n’est pas parfaite, mais reste assez élégante et n’est pas trop lourde à mettre en place.
Après, je vous laisse tester et me dire ce que vous en pensez dans les commentaires.

Allez, salut les astronautes :)

--

--