69 votes

Comment créer des méthodes à arguments variables en Objective-C

Peut-être que cela sera simple pour la plupart d'entre vous, mais pourriez-vous donner un exemple de création de méthodes similaires (en Objective-C) et de fonctions en C pour créer des fonctions telles que NSString 's stringWithFormat: ou NSLog() .

Juste pour rappeler :

[NSString stringWithFormat:@"example tekst %i %@ %.2f", 122, @"sth", 3.1415"];
NSLog(@"account ID %i email %@", accountID, email);

Je voudrais créer le similaire à NSString La méthode de l'UE stringWithFormat: , NSURL - urlWithFormat .

134voto

Williham Totland Points 15798

On les appelle généralement "fonctions variadiques" (ou méthodes, en quelque sorte).

Pour le créer, il suffit de fin votre déclaration de méthode avec , ... , comme dans

- (void)logMessage:(NSString *)message, ...;

A ce stade, vous voulez probablement l'envelopper dans un printf -car l'implémentation d'une de ces fonctions à partir de zéro est, au mieux, difficile.

- (void)logMessage:(NSString *)format, ... {
  va_list args;
  va_start(args, format);
  NSLogv(format, args);
  va_end(args);
}

Notez l'utilisation de NSLogv et non NSLog ; considérer NSLog(NSString *, ...); vs NSLogv(NSString *, va_list); ou si vous voulez une chaîne de caractères ; initWithFormat:arguments: sur NSString * .


Si, par contre, vous ne travaillez pas avec des chaînes de caractères, mais plutôt avec quelque chose comme

+ (NSArray *)arrayWithObjects:(id)object, ... NS_REQUIRES_NIL_TERMINATION;

les choses deviennent beaucoup plus faciles.

Dans ce cas, au lieu d'un vprintf -utilisez une boucle passant par args en assumant l'identité au fur et à mesure, et en les analysant comme vous le feriez dans n'importe quelle boucle.

- (void)logMessage:(NSString *)format, ... {
  va_list args;
  va_start(args, format);

  id arg = nil;
  while ((arg = va_arg(args,id))) {
  /// Do your thing with arg here
  }

  va_end(args);
}

Ce dernier exemple, bien sûr, suppose que la liste va_args est terminée par nil.

Note : Pour que cela fonctionne, vous devez pourrait doivent inclure <stdarg.h> Mais si ma mémoire est bonne, cela est inclus dans NSLogv, ce qui signifie qu'il est inclus dans "Foundation.h", donc aussi dans "AppKit.h" et "Cocoa.h", ainsi que dans un certain nombre d'autres fichiers ; cela devrait donc fonctionner dès le départ.

4 votes

Une chose à mentionner ici, c'est que le premier paramètre NSString est le format, et que les autres sont passés en argument variable. Donc, avant d'entrer dans la boucle for, vous avez un paramètre à gérer.

0 votes

Cependant, est-il possible d'éviter le problème de la terminaison " nil " ? Par exemple, obtenir la longueur des arguments de la variable ?

0 votes

@karim : Il n'est pas possible avec les varargs C de connaître le nombre et les types des arguments. La fonction appelée doit d'une manière ou d'une autre connaître les types et savoir quand s'arrêter.

23voto

M-frankied Points 251
- (void)methodWithFormat:(NSString*)format, ... {
  va_list args;
  va_start(args,format);
  //loop, get every next arg by calling va_arg(args,<type>)
  // e.g. NSString *arg=va_arg(args,NSString*) or int arg=(args,int)
  va_end(args);
}

Si vous voulez passer les arguments de la variable à stringWithFormat :, utilisez quelque chose comme :

NSString *s=[[[NSString alloc] initWithFormat:format arguments:args] autorelease];

2 votes

Version ARC : NSString *s=[[NSString alloc] initWithFormat:format arguments:args] ;

12voto

karim Points 4704

Une chose à mentionner ici est que le premier paramètre NSString vient en tant que format, et les autres sont passés dans l'argument variable, n'est-ce pas ? Donc, avant d'entrer dans la boucle for, vous avez un paramètre à gérer.

- (NSString *) append:(NSString *)list, ...
{
    NSMutableString * res = [NSMutableString string];
    [res appendString:list];

    va_list args;
    va_start(args, list);
    id arg = nil;

    while(( arg = va_arg(args, id))){
        [res appendString:arg];
    }
    va_end(args);
    return res;
}

- (void) test_va_arg
{
    NSString * t = [self append:@"a", @"b", @"c", nil];
    STAssertEqualObjects(@"abc", t, @"");
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X