Constructeur de commodité... avec arguments variables (va_arg)

AliGatorAliGator Membre, Modérateur
Bonjour,

Voilà  j'ai une petite question, j'ai l'habitude quand je conçois mes classes de mettre des constructeurs de commodité, qui se contentent d'appeller alloc/init.../autorelease.

Par exemple pour une hypothétique classe Book :
-(id)initWithTitle:(NSString*)title author:(NSString*)author { ... }<br />+(id)bookWithTitle:(NSString*)title author:(NSString*)author<br />{ return [[[Book alloc] initWithTitle:title author:author] autorelease]; }
Et du coup toutes mes méthodes de commodité sont simples et tiennent en une seule ligne, qui appelle alloc+init...+autorelease.


Mais voilà , là  j'ai un constructeur avec nombre variable d'argument, et je voudrais faire aussi un constructeur de commodité. Voici le proto de mes méthodes :
typedef enum { TPDirectionEnd=0, TPDirectionUp, TPDirectionLeft, ... } TPDirection;<br /><br />-(id)initWithName:(NSString*)name directionsList:(TPDirection)firstDir, ... NS_REQUIRES_NIL_TERMINATION;<br />+(id)gestureWithName:(NSString*)name directionsList:(TPDirection)firstDir, ... NS_REQUIRES_NIL_TERMINATION;
Mais du coup... comment implémenter mon constructeur de commodité "gestureWithName:directionsList:" pour qu'il appelle mon constructeur dédié "initWithname:directionsList:", quand j'ai un nombre variable d'arguments parsés par va_start/va_arg/va_end ?

Des idées ?

Réponses

  • LexxisLexxis Membre
    07:09 modifié #2
    Salut !

    Passer par un NSArray peut être...

    Je ferais en sorte que les constructeurs initWithName et gestureWithName appele un constructeur désigné de la forme:
    - (id)initWithName:(NSString *)name directionsListArray:(NSArray *)array{<br />...<br />}
    


    Les fonctions acceptants le nombre de params variables se chargeant de créer le NSArray....
  • AliGatorAliGator Membre, Modérateur
    07:09 modifié #3
    J'y ai pensé... Mais en fait le truc c'est que je veux gérer une liste d'enums / d'entiers
    J'ai un enum TPDirection, et j'en construis une sorte de chaà®ne, qui en gros décrit une suite de directions ("haut", puis "droite", puis "haut", puis "gauche", ...)

    Si je passe par un NSArray, faut que j'encapsule chaque enum dans un NSNumber pour le mettre dans mon NSArray... ça va me faire des appels de 3km pour construire ma chaà®ne de TPDirections !
    Le but c'est de pouvoir construire une "gesture" simplement en mettant les enums les uns à  la suite des autres, donc que l'appel au constructeur soit pas non plus chargé ;)

    En fait en interne d'ailleurs, plutôt que de garder cette chaà®ne dans un NSArray (et donc d'encapsuler chaque enum dans un NSNumber, ce qui serait lourd y compris aussi pour les manipuler plus tard d'autant que j'ai pas mal à  les manipuler dans tous les sens), j'ai choisi d'utiliser les NSIndexPath pour stocker ma chaà®ne d'enums.

    J'ai d'ailleurs pensé passer un NSIndexPath à  mon constructeur... mais pour construire un NSIndexPath avec une liste d'entiers directement, il faut lui passer un tableau C d'entiers (et le nombre d'éléments de ce tableau)... tableau qu'il faut donc construire avant d'appeler le constructeur en question... donc c'est pas mieux, ça fait pas propre/simple à  appeler non plus je trouve !
  • AliGatorAliGator Membre, Modérateur
    septembre 2009 modifié #4
    Bon, en fait j'ai trouvé (en cherchant du côté C et non Objective-C en fait) : on ne peut pas passer les variables-arguments dans "..." directement à  une autre fonction avec variadic-arguments "...". Mais par contre on peut tout à  fait passer un va_list.

    Donc l'idée est la suivante :

    Fichier.h
    typedef enum { TPDirectionEnd=0, TPDirectionUp, TPDirectionLeft, ... } TPDirection;<br /><br />@interface Gesture : NSObject<br />{<br />  //...<br />  NSIndexPath* directionsList;<br />}<br />-(id)initWithName:(NSString*)name directionsList:(TPDirection)firstDir, ... NS_REQUIRES_NIL_TERMINATION;<br />+(id)gestureWithName:(NSString*)name directionsList:(TPDirection)firstDir, ... NS_REQUIRES_NIL_TERMINATION;<br />@end
    


    Fichier.m
    @interface Gesture (Private)<br />-(id)initWithName:(NSString*)name firstDirection:(TPDirection)firstDir otherDirections:(va_list)vargs;<br />@end<br /><br />@implementation Gesture<br /><br />// constructeur classique (public)<br />-(id)initWithName:(NSString*)name directions:(TPDirection)firstDir, ...<br />{<br />  va_list vargs;<br />  va_start(vargs, firstDir);<br />  id obj = [self initWithName:name firstDirection:firstDir otherDirections:vargs];<br />  va_end(vargs);<br />  return obj;<br />}<br /><br />// constructeur de commodité (public)<br />+(id)gestureWithName:(NSString*)name directions:(TPDirection)firstDir, ...<br />{<br />  va_list vargs;<br />  va_start(vargs, firstDir);<br />  id obj = [[[TPGesture alloc] initWithName:name firstDirection:firstDir otherDirections:vargs] autorelease];<br />  va_end(vargs);<br />  return obj;<br />}<br /><br /><br />//  code mutualisé entre constructeur dédié et constructeur de commodité (privé)<br />-(id)initWithName:(NSString*)name firstDirection:(TPDirection)firstDir otherDirections:(va_list)vargs;<br />{<br />  // le code réel du constructeur dédié<br />  if ( (self = [super init]) != nil )<br />  {<br />    ... pas besoin de va_start du coup ici<br />    TPDirection dir;<br />    while( 0 != (dir = va_arg(vargs, TPDirection)) )<br />    {<br />      // traitement des arguments<br />    }<br />&nbsp; &nbsp; ... pas besoin de va_end du coup ici<br />  }<br />  return self;<br />}<br /><br />@end
    


    Voilà  :)
Connectez-vous ou Inscrivez-vous pour répondre.