web-dev-qa-db-fra.com

Comment créer des méthodes d'argument variable dans Objective-C

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

Juste pour rappel:

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

Je voudrais créer une méthode similaire à celle de NSStringstringWithFormat:, NSURL - urlWithFormat.

57
Chris Rutkowski

Ce qu'on appelle généralement ces "fonctions variadiques" (ou méthodes, pour ainsi dire).

Pour créer ceci, il suffit de terminer votre déclaration de méthode avec , ..., Comme dans

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

À ce stade, vous souhaiterez probablement l'envelopper dans une fonction semblable à printf, car l'implémentation de l'une de celles-ci à partir de zéro est, au mieux.

- (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érez NSLog(NSString *, ...); vs NSLogv(NSString *, va_list);, ou si vous voulez une chaîne; initWithFormat:arguments: Sur NSString *.


Si, en revanche, vous ne travaillez pas avec des chaînes, mais plutôt quelque chose comme

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

les choses deviennent beaucoup plus faciles.

Dans ce cas, au lieu d'une fonction de style vprintf, utilisez une boucle passant par args, en supposant id au fur et à mesure, et analysez-les 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 échantillon, bien sûr, suppose que la liste va_args est terminée par zéro.

Remarque: Pour que cela fonctionne, vous devrez inclure <stdarg.h>; mais si la mémoire est bonne, cela est inclus dans le cadre de NSLogv, ce qui signifie qu'il descend par le biais de "Foundation.h", donc également "AppKit.h" et "Cocoa.h", ainsi que plusieurs autres; donc cela devrait fonctionner hors de la boîte.

119
Williham Totland
- (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 souhaitez passer les arguments variables à stringWithFormat:, utilisez quelque chose comme:

NSString *s=[[[NSString alloc] initWithFormat:format arguments:args] autorelease];
20
M-frankied

Une chose à mentionner ici est que le premier paramètre NSString vient ici sous forme de format, et les autres sont passés dans l'argument variable. droite? Donc, avant d'entrer dans la boucle for, vous devez gérer un paramètre.

- (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, @"");
}
8
karim