Blog d'un développeur multi-support

[DIM] pour les intimes :)

iPhone & Delegate

Bonjour,

Voici juste un petit « How to » pour comprendre et jour avec les 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 :

  1. 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 ».
  2. 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.
  3. Dans la classe Detail : Appeller lors du click les méthodes « delegate » sur notre protocole.
  4. 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 : , , , ,