32 votes

Comment créer une NSString à partir d'une chaîne de format comme @ "xxx =% @, yyy =% @" et une NSArray d'objets?

Existe-t-il un moyen de créer une nouvelle NSString à partir d'une chaîne de format telle que @ "xxx =% @, yyy =% @" et une NSArray d'objets?

Dans la classe NSSTring, il existe de nombreuses méthodes comme:

 - (id)initWithFormat:(NSString *)format arguments:(va_list)argList
- (id)initWithFormat:(NSString *)format locale:(id)locale arguments:(va_list)argList
+ (id)stringWithFormat:(NSString *)format, ...
 

mais aucun d'entre eux ne prend un NSArray comme argument, et je ne trouve pas de moyen de créer une va_list à partir d'un NSArray ...

46voto

Peter N Lewis Points 12025

Il n'est en fait pas difficile de créer une va_list à partir d'un NSArray. Voir l' excellent article de Matt Gallagher sur le sujet.

Voici une catégorie NSString pour faire ce que vous voulez:

 @interface NSString (NSArrayFormatExtension)

+ (id)stringWithFormat:(NSString *)format array:(NSArray*) arguments;

@end

@implementation NSString (NSArrayFormatExtension)

+ (id)stringWithFormat:(NSString *)format array:(NSArray*) arguments
{
    char *argList = (char *)malloc(sizeof(NSString *) * arguments.count);
    [arguments getObjects:(id *)argList];
    NSString* result = [[[NSString alloc] initWithFormat:format arguments:argList] autorelease];
    free(argList);
    return result;
}

@end
 

Alors:

 NSString* s = [NSString stringWithFormat:@"xxx=%@, yyy=%@" array:@[@"XXX", @"YYY"]];
NSLog( @"%@", s );
 

37voto

SolidSun Points 475

Basé sur cette réponse en utilisant le comptage de référence automatique (ARC): http://stackoverflow.com/a/8217755/881197

Ajoutez une catégorie à NSString avec la méthode suivante:

 + (id)stringWithFormat:(NSString *)format array:(NSArray *)arguments
{
    NSRange range = NSMakeRange(0, [arguments count]);
    NSMutableData *data = [NSMutableData dataWithLength:sizeof(id) * [arguments count]];
    [arguments getObjects:(__unsafe_unretained id *)data.mutableBytes range:range];
    NSString *result = [[NSString alloc] initWithFormat:format arguments:data.mutableBytes];
    return result;
}
 

16voto

Panagiotis Korros Points 3073

Une solution qui m'est venue à l'esprit est que je pourrais créer une méthode qui fonctionne avec un grand nombre fixe d'arguments comme:

 + (NSString *) stringWithFormat: (NSString *) format arguments: (NSArray *) arguments {
    return [NSString stringWithFormat: format ,
          (arguments.count>0) ? [arguments objectAtIndex: 0]: nil,
          (arguments.count>1) ? [arguments objectAtIndex: 1]: nil,
          (arguments.count>2) ? [arguments objectAtIndex: 2]: nil,
          ...
          (arguments.count>20) ? [arguments objectAtIndex: 20]: nil];
}
 

Je pourrais également ajouter une vérification pour voir si la chaîne de format a plus de 21 caractères '%' et lever une exception dans ce cas.

4voto

Quinn Taylor Points 29688

@Chuck est correct sur le fait que vous ne pouvez pas convertir un NSArray en varargs. Cependant, je ne recommande pas la recherche pour le modèle de la %@ dans la chaîne et de le remplacer à chaque fois. (En remplacement de caractères au moyen d'une chaîne est généralement tout à fait inefficace, et pas une bonne idée si vous pouvez accomplir la même chose de façon différente.) Voici un moyen plus efficace pour créer une chaîne de caractères au format que vous décrivez:

NSArray *array = ...
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:[array count]];
for (id object in array) {
    [newArray addObject:[NSString stringWithFormat:@"x=%@", [object description]]];
}
NSString *composedString = [[newArray componentsJoinedByString:@", "] retain];
[pool drain];

J'ai inclus l'autorelease pool pour un bon entretien, depuis un autoreleased chaîne sera créé pour chaque entrée de ce tableau, et la mutable tableau est autoreleased ainsi. Vous pouvez facilement faire cela en une méthode/fonction et revenir composedString sans retenue, et de gérer l'autorelease ailleurs dans le code si vous le souhaitez.

4voto

BrettThePark Points 213

La réponse de solidsun fonctionnait bien, jusqu'à ce que j'aille compiler avec une architecture 64 bits. Cela a provoqué une erreur:

EXC_BAD_ADDRESS type EXC_I386_GPFLT

La solution était d'utiliser une approche légèrement différente pour passer la liste des arguments à la méthode:

 + (id)stringWithFormat:(NSString *)format array:(NSArray*) arguments;
{
     __unsafe_unretained id  * argList = (__unsafe_unretained id  *) calloc(1UL, sizeof(id) * arguments.count);
    for (NSInteger i = 0; i < arguments.count; i++) {
        argList[i] = arguments[i];
    }

    NSString* result = [[NSString alloc] initWithFormat:format, *argList] ;//  arguments:(void *) argList];
    free (argList);
    return result;
}
 

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