ちょっと前だが、フェンリルの開発者ブログでこんな記事があった。
文字列を Objective-C っぽくクールに作る
ここに書かれている方法はその通りでこういう実装は見習いたいものだと思う。
特にNSArrayを使って文字列の配列を作成してから[NSArray componentsJoinedByString:] を使って連結するやり方は、先頭または末尾を特別扱いする必要がないのであらかじめいくつデータがあるのかわからない場合などにとても有用だ。
が、ふと別の観点から見たらどうなんだろう?と考えてみた。速度面である。
それぞれのやり方で実行時間を計測したらこうなった。
2.6GHz Intel Core i7
MacOS X 10.8.2
#import
#import
#define TEST 0
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *aString;
uint64_t start, elapsed;
mach_timebase_info_data_t base;
mach_timebase_info(&base);
start = mach_absolute_time();
for ( int i = 0; i < 100; i++ ) {
aString = @"";
#if TEST == 0
NSMutableString *muString = [NSMutableString string];
for ( int j = 0; j < 100; j++ ) {
[muString appendFormat:@"Time Test (%d)\n",j];
}
// time = 4343708(nsec)
#elif TEST == 1
for ( int j = 0; j < 100; j++ ) {
aString = [aString stringByAppendingFormat:@"Time Test (%d)\n",j];
}
// time = 25425541(nsec)
#elif TEST == 2
for ( int j = 0; j < 100; j++ ) {
aString = [NSString stringWithFormat:@"%@\nTime Test (%d)",aString,j];
}
// time = 19513834(nsec)
#elif TEST == 3
NSMutableArray *anArray = [NSMutableArray array];
for ( int j = 0; j < 100; j++ ) {
[anArray addObject:[NSString stringWithFormat:@"Time Test (%d)",j]];
}
aString = [anArray componentsJoinedByString:@"\n"];
// time = 13281454(nsec)
#elif TEST == 4
NSMutableArray *anArray = [NSMutableArray arrayWithCapacity:100];
for ( int j = 0; j < 100; j++ ) {
[anArray addObject:[NSString stringWithFormat:@"Time Test (%d)",j]];
}
aString = [anArray componentsJoinedByString:@"\n"];
// time = 12225972(nsec)
#endif
}
elapsed = mach_absolute_time() - start;
uint64_t nsec = elapsed * base.numer / base.denom;
printf("time = %lld(nsec)\n",nsec);
}
return 0;
}
100行の文字列を作成するのを100回繰り返す場合。実行時間だけで言うと、
[NSMutableString appendFormat] = 4343708(nsec)
[NSArray componentsJoinedByString:] = 13281454(nsec)
[NSString stringWithFormat:] = 25425541(nsec)
[aString stringByAppendingFormat:@"Time Test (%d)\n",j] = 19513834(nsec)
の順になる。
意外なことに[NSMutableString appendFormat]を使うのが一番いいという結果になった。メモリ管理の効率がいいせいなのかもしれない。
でもよっぽど実行時間を節約しなければならない状況でなければ[NSArray componentsJoinedByString:] を使うのがいいという考えは変わらない。