Основываясь на этот вопрос SO, заданный несколько часов назад, я решили реализовать swizzled метод, который позволит мне использовать отформатированный NSString
в качестве аргумента формата в stringWithFormat
и не нарушить его при пропуске одной из нумерованных ссылок на аргумент (%1$@, %2$@
)
У меня это работает, но это первая копия, и, учитывая, что этот метод потенциально будет вызываться сотни тысяч раз за запуск приложения, мне нужно оттолкнуть это от некоторых экспертов, чтобы увидеть, есть ли у этого метода какие-либо красные флажки. , серьезные потери производительности или оптимизации
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
@implementation NSString (UAFormatOmissions)
+ (id)uaStringWithFormat:(NSString *)format, ... {
if (format != nil) {
va_list args;
va_start(args, format);
// $@ is an ordered variable (%1$@, %2$@...)
if ([format rangeOfString:@"$@"].location == NSNotFound) {
//call apples method
NSString *s = [[[NSString alloc] initWithFormat:format arguments:args] autorelease];
va_end(args);
return s;
}
NSMutableArray *newArgs = [NSMutableArray arrayWithCapacity:NUMARGS(args)];
id arg = nil;
int i = 1;
while (arg = va_arg(args, id)) {
NSString *f = [NSString stringWithFormat:@"%%%d\$\@", i];
i++;
if ([format rangeOfString:f].location == NSNotFound) continue;
else [newArgs addObject:arg];
}
va_end(args);
char *newArgList = (char *)malloc(sizeof(id) * [newArgs count]);
[newArgs getObjects:(id *)newArgList];
NSString* result = [[[NSString alloc] initWithFormat:format arguments:newArgList] autorelease];
free(newArgList);
return result;
}
return nil;
}
Основной алгоритм:
- найдите строку формата для переменных
%1$@
,%2$@
, выполнив поиск%@
- если не найдено, вызовите обычный stringWithFormat и верните
- иначе, переберите аргументы
- если формат имеет переменную позиции (
%i$@
) для позиции i, добавьте аргумент в новый массив аргументов - в противном случае не добавляйте аргумент
- возьмите новый массив аргументов, преобразуйте его обратно в
va_list
и вызовитеinitWithFormat:arguments:
, чтобы получить правильную строку.
Идея состоит в том, что вместо этого я буду запускать все вызовы [NSString stringWithFormat:]
через этот метод.
Многим это может показаться ненужным, но нажмите на указанный вопрос SO (первая строка), чтобы увидеть примеры того, почему мне нужно это сделать.
Идеи? Мысли? Лучшая реализация? Лучшие решения?
arrayWithCapacity:
иstringWithFormat:
? - person dreamlax   schedule 01.06.2010NUMARGS
делает то, что вы думаете? - person dreamlax   schedule 01.06.2010NUMARGS(args)
, вы каждый раз получали бы 1.__VA_ARGS__
расширяется до аргументов, переданных самому макросу, а вы предоставляете только один аргумент. Вы вставляете объект типаva_list
в массивint
; еслиva_list
реализовано как указатель (я уверен, что так и есть в большинстве систем), вы должны получить предупреждение о преобразовании без явного приведения. - person dreamlax   schedule 01.06.2010