Protocole & Delegate

Bonjour,



essayent de mieux comprendre le fonctionnement des protocoles et des delegates, j'essaye de mettre un place un exemple test.



Voila mon protocole:
[color=#73492c]#import [/color]&lt;Foundation/Foundation.h&gt;<br />
<br />
[color=#b41ca4]@protocol[/color] helloDelegate &lt;[color=#7134aa]NSObject[/color]&gt;<br />
<br />
-([color=#7134aa]NSString[/color] *)getTexte;<br />
<br />
@end




La classe qui implémente ce protocole:



hello.h
[color=#73492c]#import [/color]&lt;Foundation/Foundation.h&gt;<br />
[color=#c72c25][color=#73492c]#import [/color]&quot;helloDelegate.h&quot;[/color]<br />
<br />
[color=#578187][color=#b41ca4]@interface[/color][color=#000000] hello : [/color][color=#7134aa]NSObject[/color][color=#000000] &lt;[/color]helloDelegate[color=#000000]&gt;[/color][/color]<br />
<br />
-([color=#7134aa]NSString[/color] *)getTexte;<br />
<br />
@end




hello.m
<br />
<br />
-([color=#7134aa]NSString[/color] *)getTexte<br />
{<br />
	[color=#7134aa]NSString[/color] * bonjour=[color=#c72c25]@&quot;hello&quot;[/color];<br />
	[color=#b41ca4]return[/color] bonjour;<br />
}<br />




Et ma classe test:



testViewControlle.h
<br />
<br />
[color=#c72c25][color=#73492c]#import [/color]&lt;UIKit/UIKit.h&gt;[/color]<br />
[color=#c72c25][color=#73492c]#import [/color]&quot;helloDelegate.h&quot;[/color]<br />
[color=#c72c25][color=#73492c]#import [/color]&quot;hello.h&quot;[/color]<br />
<br />
<br />
<br />
[color=#578187][color=#b41ca4]@interface testV[/color][color=#000000]iewController : [/color][color=#000000]UIViewController{[/color][/color]<br />
<br />
[color=#578187][color=#000000]	[/color][color=#b41ca4]id[/color][color=#000000]&lt;[/color]helloDelegate[color=#000000]&gt; delegate;[/color][/color]<br />
}<br />
[color=#b41ca4]@end[/color]<br />




viewController.m
<br />
<br />
[color=#c72c25][color=#73492c]#import [/color]&quot;testViewController.h&quot;[/color]<br />
<br />
[color=#c72c25][color=#B41CA4]@implementation[/color] testViewController[/color]<br />
[color=#c72c25]...[/color]<br />
<br />
[color=#C72C25]- ([color=#b41ca4]void[/color])viewDidLoad[/color]<br />
[color=#C72C25]{[/color]<br />
[color=#401082][color=#000000]	[[/color][color=#b41ca4]super[/color][color=#000000] [/color]viewDidLoad[color=#000000]];[/color][/color]<br />
[color=#C72C25][color=#000000]	[/color][color=#401082]NSLog[/color][color=#000000]([/color]@&quot;Bonjour: %@&quot;[color=#000000],[[/color][color=#578187]delegate[/color][color=#000000] [/color][color=#38595d]getTexte[/color][color=#000000]]);[/color][/color]<br />
[color=#C72C25][color=#000000]}[/color][/color]<br />
[color=#C72C25][color=#000000]....[/color][/color]<br />




Je pensais avoir bien fait, mais visiblement non, rien ne s'affiche!!! "Bonjour: (nulle)"



Quelqu'un pour me corriger ?

Réponses

  • yoannyoann Membre
    Et as-tu bien penser à  régler ton delegate ? Dans les grandes lignes ton code m'a l'air bon (même s'il est préférable de tester qu'un delegate supporte bien une méthode avant de l'appeler).
  • AliGatorAliGator Membre, Modérateur
    'yoann' a écrit:


    Et as-tu bien penser à  régler ton delegate ?
    En effet il manque l'affectation du delegate. Il faut instancier un objet "Hello" (alloc+init) quelque part, et l'affecter au delegate de TestViewController ensuite, avant de pouvoir l'utiliser, histoire que delegate ne soit pas nil.


    'yoann' a écrit:
    même s'il est préférable de tester qu'un delegate supporte bien une méthode avant de l'appeler
    Ce n'est utile que pour les méthodes indiquées @optional dans le delegate, ça. Si elles sont @required (comme c'est le cas par défaut), le compilateur le dira si l'objet n'implémente pas la méthode image/wink.png' class='bbc_emoticon' alt=';)' />
  • D'accord,



    et dans le cas ou plusieurs objets implémente le même protocole ? Il faudra les instancié autant de fois et les affecter au delegate de TestViewController ensuite, au fur à  mesure que j'en ai besoin ?
  • juin 2012 modifié #5
    Quand tu veux que plusieurs objets puissent être informés des traitements d'un autre objet, il faut passer par le NSNotificationCenter. Si tu es sûr d'avoir du 1/1 dans ce cas une property "delegate" suffit.





    Petite remarque quand même, je ne veux plus revoir des méthodes du genre "- (NSString*)getText".

    Si tu veux utiliser le terme 'get' c'est que tu vas passer un pointeur en argument (cf -getValue: de NSValue).
  • yass_1988yass_1988 Membre
    juin 2012 modifié #6
    Oky



    et sinon dernière question, imaginons que j'ai un protocole nommé ActionDelegate implémenter par RenameAction et maintenant je suis dans une autre classe "x" qui comprend une méthode dont le type de retour serais de type ActionDelegate.

    Est ce que syntaxiquement c'est correct d'écrire:


    -(id&lt;ActionDelegate&gt;delegate)nomDeMaMéthode:paramètres;
    


    ou alors
    -(id&lt;ActionDelegate&gt;)nomDeMaMéthode:paramètres;
    




    Ou alors faut rajouter autre chose ?
  • AliGatorAliGator Membre, Modérateur
    Je t'invite à  suivre mon tuto sur le sujet qui explique les principes des delegate et leur intérêt :

    http://forums.mediabox.fr/wiki/tutoriaux/apple/protocol
  • yass_1988yass_1988 Membre
    juin 2012 modifié #8
    Je l'ai déjà  lu le tuto (D'ailleur il m'a permis de mieux saisir la notion des protocoles et des delegates), mais j'ai pas trouvé de réponse à  mon cas précis, en faite je m'inspire un peu de JAVA.



    Une méthode d'une classe "x"
    <br />
    [color=#666600]-([/color][color=#000000]id[/color][color=#666600]&lt;[/color][color=#660066]ActionDelegate[/color][color=#666600]&gt;)[/color][color=#000000]nomDeMaM[/color][color=#666600]é[/color][color=#000000]thode[/color][color=#666600]:[/color][color=#000000]param[/color][color=#666600]è[/color][color=#000000]tres[/color]<br />
    [color=#000000]{[/color]<br />
    [color=#000000]	  RenameAction * Ra=[[RenameAction alloc]init][/color];<br />
    	 return Ra;<br />
    }<br />
    




    Sachant que RenameAction implémente ActionDelegate.



    Je sais qu'en JAVA par exemple, une classe qui implémente une interface, et une méthode d'une autre classe qui retourne une instance de la classe qui implémente l'interface. On peut spécifier en type de retour de la méthode, le nom de l'interface.



    Voila en faite ma question étais plus dans ce sens là .
  • CéroceCéroce Membre, Modérateur
    Oui, c'est possible, avec la notation que tu as utilisée, mais je n'ai jamais rien écrit de tel, c'est pourquoi nous nous demandons un peu où tu veux en venir.
  • 'Céroce' a écrit:


    Oui, c'est possible, avec la notation que tu as utilisée, mais je n'ai jamais rien écrit de tel, c'est pourquoi nous nous demandons un peu où tu veux en venir.




    Quand tu parle de notation jamais utilisé, tu parle de ça ?


    <br />
    -(id&lt;protocol&gt;)method;<br />
    




    Personnellement je m'en sert souvent, surtout quand tu crée des API par protocole et non par interface et que tu combine le tout avec des builder.
  • yass_1988yass_1988 Membre
    juin 2012 modifié #11
    En faite ce que je veux c'est avoir un niveau d'abstraction, ne jamais manipulé l'objet concret, juste ces méthodes.

    Tout comme je ferais en JAVA avec les interfaces, pour ceux qui connaissent.

    Le faite que j'ai comme type de retour id<ActionDelegate>, c'est que l'objet qui va encapsuler le retour de ma méthode, ne sache concrétement qu'il manipule RenameAction.

    Après est ce que ce que j'ai écris répond à  mon problème, je ne sais pas.

    Après pour la suite, en ce qui concerne l'objet qui va encapsuler l'objet retourner par la méthode, j'hésite:



    class x:
    [color=#666600][color=#666600]-([/color][/color][color=#000000][color=#000000]id[/color][/color][color=#666600][color=#666600]&lt;[/color][/color][color=#660066][color=#660066]ActionDelegate[/color][/color][color=#666600][color=#666600]&gt;)[/color][/color][color=#000000][color=#000000]nomDeMaM[/color][/color][color=#666600][color=#666600]é[/color][/color][color=#000000][color=#000000]thode[/color][/color][color=#666600][color=#666600]:[/color][/color][color=#000000][color=#000000]param[/color][/color][color=#666600][color=#666600]è[/color][/color][color=#000000][color=#000000]tres[/color][/color]<br />
    [color=#000000][color=#666600]{[/color][/color]<br />
    [color=#000000][color=#000000]		  [/color][color=#660066]RenameAction[/color][color=#000000] [/color][color=#666600]*[/color][color=#000000] [/color][color=#660066]Ra[/color][color=#666600]=[[[/color][color=#660066]RenameAction[/color][color=#000000] alloc[/color][color=#666600]][/color][color=#000000]init[/color][color=#666600]][/color][/color][color=#666600];[/color]<br />
    [color=#000000]		 [/color][color=#000088]return[/color][color=#000000] [/color][color=#660066]Ra[/color][color=#666600];[/color]<br />
    <br />
    }
    


    class y:
    -(id&lt;ActionDelegate&gt;) delegate<br />
    self-&gt;delegate=[x nomDeMaMéthode:paramétre]
    




    ou alors:





    class x:
    [color=#666600]-([/color][color=#000000]RenameAction *[/color][color=#666600][color=#666600])[/color][/color][color=#000000][color=#000000]nomDeMaM[/color][/color][color=#666600][color=#666600]é[/color][/color][color=#000000][color=#000000]thode[/color][/color][color=#666600][color=#666600]:[/color][/color][color=#000000][color=#000000]param[/color][/color][color=#666600][color=#666600]è[/color][/color][color=#000000][color=#000000]tres[/color][/color]<br />
    [color=#000000][color=#666600]{[/color][/color]<br />
    [color=#000000][color=#000000]		  [/color][color=#660066]RenameAction[/color][color=#000000] [/color][color=#666600]*[/color][color=#000000] [/color][color=#660066]Ra[/color][color=#666600]=[[[/color][color=#660066]RenameAction[/color][color=#000000] alloc[/color][color=#666600]][/color][color=#000000]init[/color][color=#666600]][/color][/color][color=#666600];[/color]<br />
    [color=#000000]		 [/color][color=#000088]return[/color][color=#000000] [/color][color=#660066]Ra[/color][color=#666600];[/color]<br />
    <br />
    }
    


    class y:
    -(id&lt;ActionDelegate&gt;) delegate<br />
    self-&gt;delegate=[x nomDeMaMéthode:paramétre]
    




    Sauf que si la première est correcte, mon niveau d'abstraction sera au plus haut, or si je prend la deuxième option, qui elle est sur de fonctionner, mon niveau d'abstraction devient très bas.
  • CéroceCéroce Membre, Modérateur
    'yoann' a écrit:


    Quand tu parle de notation jamais utilisé, tu parle de ça ?


    Non, ce n'est pas de la notation dont je parlais, mais de l'exemple que yass nous donnait, où on renvoie une instance d'une classe conforme à  ce protocole.
  • AliGatorAliGator Membre, Modérateur
    Oui je me sers également de ce genre de construction, une méthode qui au lieu d'avoir un type de retour explicite (nom de la classe de l'objet retourné) retourne un id<protocol>. Cela permet plus d'abtraction.



    Par contre, histoire de bien préciser les choses pour yass_1988 :
    • Ce que tu décris dans ton précédent message utilise la notion de protocole (ce qu'en Java on appelle interfaces), "id<UnProtocole>" est un type qui veux dire "un objet de n'importe quel type (id) du moment qu'il se conforme au protocole UnProtocole (équivalent java ~ qu'il implémente l'interface de classe UnProtocole). Cela n'utilise en rien la notion de delegate
    • Le Design Pattern (patron de conception) delegate est une notion qui permet de déléguer à  un objet tierce des actions d'un objet principal (ou d'informer un objet tierces des actions/événements clés de l'objet principal dont il est le délégué). Par exemple, si tu utilises un UITextField, tu peux vouloir modifier le comportement quand l'utilisateur cherche à  rajouter du texte dans le TextField (par exemple pour ne pas l'autoriser à  taper certains caractères ou limiter le nombre de caractères du champ...). Pour faire ça, plutôt que de sous-classer UITextField juste pour surcharger la méthode appelée lors de la saisie d'un caractère, UITextField te propose de fournir un objet servant de délégué, et va demander à  cet objet avant l'insertion de tout texte dans le champ, le délégué ayant la possibilité de l'autoriser ou non. Cela permet donc de déléguer la responsabilité de certaines tâches à  d'autres objets (d'où le nom) sans être obligé de sous-classer. On pourrait éventuellement faire un petit parallèle avec les listeners qu'on peut trouver en Java, même si ce n'est pas le même concept, on y retrouve des similitudes
    • Après, le design pattern "Delegate" utilise les protocoles pour faire en sorte d'avoir un couplage faible entre l'objet principal et l'objet que tu choisis comme délégué de cet objet. Pour te permettre -- pour reprendre l'exemple plus haut -- de mettre n'importe quel objet en tant que delegate de UITextField, du moment qu'il répond au protocole (qu'il implémente l'interface, dirait-on en Java), sans imposer que cet objet utilisé comme délégué ne soit forcément d'une classe particulière (cela serait un couplage fort entre l'objet et son delegate, une contrainte trop contraignante)
  • 'Céroce' a écrit:


    Non, ce n'est pas de la notation dont je parlais, mais de l'exemple que yass nous donnait, où on renvoie une instance d'une classe conforme à  ce protocole.




    Oui bah justement, renvoyer une instance d'une classe conforme à  un protocole c'est ce que l'on va faire dans un builder / une factory method.
  • Merci Ali,

    bon du coup, je reste sur ma 1er option.
Connectez-vous ou Inscrivez-vous pour répondre.