Bonjour,
Voici juste un petit « How to » pour comprendre et jour avec les delegate sur cocoa.
Admettons vous avez une classe « ListingController » qui hérite d’une UIViewController qui gère une liste d’élément et que vous avez une classe « DetailController » qui hérite aussi d’une UIViewController mais qui donne le detail de l’élément cliqué.
Vous voulez que lorsqu’on click sur un bouton posé sur la vue Détail revenir à la liste principal, puis la recharger. Revenir à la vue principal est assez simple il suffit de crée une méthode « IBAction » dans le controller Detail, liée le bouton à cette méthode via Interface builder puis écrire :
1 2 3 | -(IBAction)goHome { [self.view removeFromSuperview]; } |
Et le tour est joué mais bon, la liste n’est pas rechargé pour autant et il n’y a pas eu la levé d’un évènement pour la classe « Liste ». C’est là que les delegate peuvent nous être utile.
Le principe est de définir des méthodes sur la classe de Detail puis les appeller/utiliser lors du click mais c’est la classe Liste qui les implémentera effectivement.
Voici la marche à suivre :
- Dans la classe Detail : Définir une ou plusieurs méthodes dite « delegate » qui devront être implémenter. On appelle ce genre de déclaration un « protocole ».
- Dans la classe Detail : Définir une propriété de classe de type « id » qui utilise le protocole. Cette propriété représente un lien vers la classe « parente » qui implémentera effectivement notre protocole.
- Dans la classe Detail : Appeller lors du click les méthodes « delegate » sur notre protocole.
- Dans la classe Liste : Implémenter les méthodes delegate dans notre classe « parente ».
Etape 1 :
Dans le fichier « DetailController.h », juste après les #import et avant @interface DetailController : UIViewController { } :
1 2 3 4 | @protocol DetailControllerDelegate @required -(void)RetourListe; @end |
Etape 2 :
Toujours dans le fichier « DetailController.h », après « @interface DetailController : UIViewController { » nous définissons une propriété que nous appellerons « delegate » :
1 | id delegate; |
puis après l’accolade définissant l’interface :
1 2 3 | @property (nonatomic,assign) id < DetailControllerDelegate > delegate; @end |
Notre propriété « delegate » est de type « id » mais « implémente » le protocole précédement utilisé.
Etape 3 :
Nous avons définit une propriété dans le fichier « .h », il faut maintenant s’en servir dans notre fichier « DetailController.m » :
1 2 3 4 5 6 7 8 9 | #import "DetailController.h" @implementation DetailController @synthesize delegate; //synthetisé une propriété signifie que le sdk créera les getters/setters pour nous -(IBAction)goHome { NSLog(@"Go home Liste"); [self.delegate RetourListe]; // dispatch l'évènement à la classe parente. [self.view removeFromSuperview]; // supprime la vue courante } |
C’est fini pour notre classe Detail ! Vous remarquerez qu’à aucun moment il n’y a de lien vers la classe « Liste ». Le couplage est donc très faible entre ces classes. Ce principe de couplage faible est assez puissant si on y réfléchi à deux fois vu que nos classes sont, de fait, totalement indépendantes vis à vis de leur « parent » (ou du contexte d’execution pour être plus bien parlant). Bon bref ça c’était le coup de pub raté pour la puissance du modèle objet.
Etape 4
Implémentons les méthodes ! Dans le fichier « ListingController.h » nous déclarons notre interface comme ceci :
1 2 3 | @interface ListingController : UIViewController < DetailControllerDelegate > { // some code } |
Et dans notre fichier « ListingController.m » il suffit d’implémenter la méthode « RetourListe ». Surtout, ne pas la déclarer dans l’interface (le fichier .h) sinon le programme se mélangera les pinceaux ! (Oui, vous utilisez deux méthodes avec le même nom ayant des portés différentes ..)
1 2 3 4 5 | -(void)RetourListe { NSLog("coucou"); // some code } |
Edit : Oups, erreur. On crée la méthode mais à un aucun moment on dit que notre classe Listing va implémenter les méthodes de detail hormis dans la déclaration (fichier.h). Il faut donc qu’à notre objet « DetailController », juste après qu’il soit instanciée, au moment du click par exemple faire un :
1 2 | DetailController*myView = [[DetailControlleralloc] initWithNibName:@"DetailView" bundle:[NSBundle mainBundle]]; myView.delegate = self; |
On définit que c’est la classe Listing (self) va implémenter les méthodes delegate de détail.
Et voilà, normallement ça doit marcher.
Ce « How to » a été écrit à partir d’un projet personnel, je ne pourrais donc pas donnée des sources qui utilisent ce concept. A l’heure où j’écrit ce billet je n’ai pas de Mac à ma disposition.
Tags : delegate, classe, objective c, iPhone, protocol