Implémenter un mécanisme de delegate

FloFlo Membre
02:46 modifié dans API AppKit #1
Bonjour à  tous,

Je me demandais juste s'il suffisait de rajouter une ivar id *delegate dans son controller et de lui envoyer les méthodes déléguées pour implémenter un mécanisme de delegate ?

Ou alors existe-t-il des protocoles à  implémenter ou une démarche spécifique à  suivre ?

Réponses

  • Philippe49Philippe49 Membre
    02:46 modifié #2
    La doc

    On implémente un protocole informel (i.e une catégorie sur NSObject)

    @interface NSObject (NSURLConnectionDelegate)<br />- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response;<br />- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;<br />- (void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;<br />- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;<br /><br />- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;<br />- (void)connectionDidFinishLoading:(NSURLConnection *)connection;<br />- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;<br /><br />- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse;<br /><br />@end<br />
    

    et on prend soin de vérifier que le delegate répond à  la méthode avant de lui envoyer
    if([delegate respondsToSelector:@selector(machin:)]) { .... }
  • AliGatorAliGator Membre, Modérateur
    02:46 modifié #3
    Beeerk vous utilisez encore les protocoles informels, vous?
    Moi depuis qu'Objective-C 2.0 est disponible, et donc depuis que les @optional ont été introduits dans les @protocols, je n'utilise que les protocoles formels (surtout depuis que je code pour iPhone qui n'utilise aussi que ça)...

    Gros avantage, pas besoin d'avoir à  vérifier que ton delegate répond à  ta méthode avant de l'appeler, en particulier pour les méthodes @required, ce qui en fait est le cas pour la plupart des cas d'utilisation.

    En plus l'utilisation des protocoles informels, et donc des catégories de NSObject (car il s'agit bien de ça en fait), a été introduite justement pour palier au manque des @optional dans les @protocol dans la première version d'Objective-C... Mais perso je suis pas fan car ça veut dire qu'on déclare les méthodes dans notre catégorie donc qu'elles sont déclarées pour toutes les sous-classe de NSObject, ça fait un peu fouilli je trouve.

    Depuis que les protocoles formels permettent aussi de mettre des méthodes @optional si vraiment on a besoin, plus de raison d'utiliser les protocoles informels à  mon goût.

    @class Toto;<br />@protocol TotoDelegate<br />-(void)toto:(Toto*) willDoSomethingWithString:(NSString*)string;<br />-(void)toto:(Toto*) didDoSomethingWithString:(NSString*)string;<br />// ...<br />@end<br /><br />@interface Toto : ParentClass<br />{<br />&nbsp; id&lt;TotoDelegate&gt; delegate;<br />}<br />-(void)doSomethingWithString:(NSString*)string;<br />@property(nonatomic, assign) id&lt;TotoDelegate&gt; delegate;<br />@end<br />
    
    @implementation Toto<br />@synthesize delegate;<br /><br />-(void)doSomethingWithString:(NSString*)string<br />{<br />&nbsp; // envoi d&#39;un message au delegate : pas besoin de vérifier qu&#39;il implémente<br />&nbsp; // la méthode, on est déjà  assuré qu&#39;il se conforme au protocole<br /><br />&nbsp; [delegate willDoSomethingWithString:string]; // inform the delegate<br />&nbsp; ... code de la méthode ... qui fait qqch avec &quot;string&quot;<br />&nbsp; [delegate didDoSomethingWithString:string]; // inform the delegate&nbsp; <br />}<br />@end
    
    Voilà  pour l'exemple pratique. L'avantage d'utiliser les protocoles formels c'est que lorsque tu affectes la propriété "delegate" de ton Toto à  un objet, il vérifie à  la compilation que l'objet se conforme au protocole (a déclaré dans son .h le nom du protocole entre chevrons), et que toutes les méthodes requises sont présentes. Dans ce cas pas besoin de vérifier que le delegate "respondsToSelector" à  chaque appel.
    // Classe qui se conforme au protocole TotoDelegate et va donc implémenter ses méthodes<br /><br />@interface MonListener &lt;TotoDelegate&gt;<br />{<br />}<br />@end<br /><br />@implementation MonListener<br />-(void)toto:(Toto*) willDoSomethingWithString:(NSString*)string<br />{<br />&nbsp; NSLog(@&quot;Attention je vais faire qqch avec la chaà®ne %@&quot;,string);<br />}<br />-(void)toto:(Toto*) didDoSomethingWithString:(NSString*)string<br />{<br />&nbsp; NSLog(@&quot;Voilà , j&#39;ai fait qqch avec %@&quot;,string);<br />}<br />@end<br /><br />...<br />// et quelquepart dans ton code pour tester :<br />{<br />&nbsp; MonListener* totoDlg = [[MonListener alloc] init]; // créer l&#39;objet qui servira de delegate<br />&nbsp; Toto* monToto = [[Toto alloc] init];<br /><br />&nbsp; monToto.delegate = totoDlg; // indiquer que c&#39;est totoDlg qui sera le delegate de monToto et donc que c&#39;est lui qui recevra les message de delegate<br />&nbsp; [monToto doSomethingWithString:@&quot;Test String&quot;];<br /><br />&nbsp; [monToto release]; // fin du test<br />&nbsp; [totoDlg release]; // on n&#39;en a plus besoin<br />}
    
  • Philippe49Philippe49 Membre
    02:46 modifié #4
    dans 1242837878:

    Beeerk vous utilisez encore les protocoles informels, vous?

    Tu as peut être raison,  la doc Obj 2.0 autorise les deux formes de protocole.
    On gagne quoi au protocole formel ? un test en moins à  l'exécution ... les warnings à  la compilation pour nous rappeler à  l'ordre ... 
  • FloFlo Membre
    02:46 modifié #5
    Merci pour cet exposé détaillé !

    Va pour le protocol formel, c'est vrai que ça cumule tous les avantages.
  • AliGatorAliGator Membre, Modérateur
    02:46 modifié #6
    dans 1242838523:

    On gagne quoi au protocole formel ? un test en moins à  l'exécution ... les warnings à  la compilation pour nous rappeler à  l'ordre ...
    Bah tout ça... plus la clareté de lecture du code (et de la génération de doc si tu utilises du headerdoc ou doxygen ou autre) et le fait que tu es assuré dès la compilation que tu as bien tout prévu comme il faut et ne risque pas d'appeler une méthode de delegate au RunTime en ayant oublié de vérifier qu'elle était implémentée par ledit delegate, ce qui est bien plus difficile à  identifier comme erreur que lorsqu'on a des warnings de compilation.

    Mais de toute façon je trouve ça aussi plus propre... et pour tout avouer... ça m'arrange aussi d'utiliser les @protocols formels puisqu'ensuite je peux utiliser mon script qui me génère les TextMacros automatiquement et me permet de générer le code associé directement :P

    Après, c'est un peu comme les @property : tu peux toujours ne pas les utiliser, mais depuis que la fonctionnalité existe, comme ça facilite la vie et surtout la lecture du code, ce serait bête de pas passer par là  et de continuer avec la bonne vieille méthode  ;)
  • psychoh13psychoh13 Mothership Developer Membre
    mai 2009 modifié #7
    Au passage, t'es quand même obligé de tester si une méthode @optional est implémenté avant de pouvoir l'utiliser... Et en général toutes les méthodes d'un delegate sont @optional, car le développeur choisit la méthode qu'il veut implémenter.

    Et pour l'anecdote, le protocol informel permet aussi d'utiliser une classe comme delegate, car les méthodes déclarées dans la classe racine (NSObject en l'occurrence) peuvent être appelées comme méthode de classe par ses sous-classes.
  • FloFlo Membre
    02:46 modifié #8
    Oui c'est vrai, mais j'ai lu ça récemment dans la doc :


    An informal protocol may be useful when all the methods are optional, such as for a delegate, but (on Mac OS X v10.5 and later) it is typically better to use a formal protocol with optional methods.


  • AliGatorAliGator Membre, Modérateur
    02:46 modifié #9
    De toute façon je trouve ça beaucoup plus lisible... et beaucoup plus objet, de toute façon, d'utiliser des @protocol. Ca permet d'avoir des contrats d'interface clairement identifiés. Et pas juste "un artifice qu'on utilise" (les catégories) "juste histoire de pas avoir des warnings "...may not respond to...", parce que pour moi les catégories ça fait un peu ça, aussi... surtout les catégories de NSObject j'ai un peu l'impression de tout mettre sur le dos de NSObject avec 15000 catégories uniquement pour ça (d'autant que ça se mélange entre les catégories faites pour les protocoles informels pour les delegates, et les "vraies" catégories uniquement pour étendre une classe existante.


    Ainsi pour moi rajouter une classe "reverseString" à  la classe NSString (pour retourner la chaà®ne dans le sens inverse par exemple, en imaginant que ça vous est utile), ou les fameuses catégories de NSString permettant de gérer le Base64... et les catégories sur NSObject, servant juste à  coutourner le problème des warnings à  l'époque où les @optional n'existait pas et donc les @protocol n'était pas utilisables pour des delegate pour lesquels on ne voulait pas imposer de tout implémenter... y'a quand même une sacrée différence de use case.

    Donc pour moi, les @protocols sont fait pour ça à  la base (et la notion de contrat d'interface dans la POO en général), donc je ne vois pas pourquoi utiliser autre chose... Les catégories de NSObjects pour les protocols informels) c'est purement historique genre paliatif avant Objective-C 2.0... ;)
  • psychoh13psychoh13 Mothership Developer Membre
    02:46 modifié #10
    Je suis tout à  fait d'accord, cependant je voudrais apporter une petite précision.

    Il y a tout de même une grosse différence entre un protocol formel et informel... Dans le cas du protocol formel, celui-ci existe à  l'exécution, il est enregistré dans le runtime avec toutes ses méthodes...
    Alors que dans le cas du protocol informel, qui n'est pas implémenté, à  l'exécution il n'existe plus, seuls les sélecteurs sont gardés et les autres informations, comme les types ont tout juste étaient utilisés par le compilateur.
Connectez-vous ou Inscrivez-vous pour répondre.