数時間前に尋ねられたこのSOの質問に基づいて、フォーマットさNSString
れたargをに取り込んstringWithFormat
で、番号付きのarg参照の1つを省略しても壊れないようにするswizzledメソッドを実装することにしました( %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$@
)がある場合は、新しいarg配列にargを追加します - それ以外の場合は、引数を追加しないでください
- 新しいarg配列を取得し、それをに変換して戻し
va_list
、呼び出しinitWithFormat:arguments:
て正しい文字列を取得します。
[NSString stringWithFormat:]
代わりに、このメソッドを介してすべての呼び出しを実行するという考え方です。
これは多くの人にとって不必要に思えるかもしれませんが、参照されているSOの質問(最初の行)をクリックして、これを行う必要がある理由の例を確認してください。
アイデア?考え?より良い実装?より良いソリューション?