数値 → 文字列変換

Objective-Cで、int値を文字列に変換する簡単な方法は2つくらいあります。
(たぶんもっとありますが、今回は以下の2つに絞ってみました。)

1. NSString.stringWithFormatを使う

NSString* str = [NSString stringWithFormat:@"%d", 100];

2. NSNumber#stringValueを使う

NSString* str = [[NSNumber numberWithInt:100] stringValue];

Google検索すると、1の方法がたくさん出てくるんですけど、ただ値を数字に変換したいだけなのに、書式化文字列を使うのって、直感的ではないというか、ちょっと無駄に見えてしまうのは私だけでしょうか?

実際、どちらの方が効率的なのでしょうか。

// 数値 → 文字列変換
// NSString.stringWithFormat と NSNumber#stringValue
// どちらが速いか試してみた。
static const int TEST_COUNT = 300000;
NSString* str;

// テスト用メイン関数
int main(int argc, const char** argv)
{
    @autoreleasepool {
        // Format
        NSDate* st1 = [NSDate date];
        
        for (int i = 0; TEST_COUNT > i; ++ i) {
            str = [NSString stringWithFormat:@"%d", i];
        }
        
        NSDate* ed1 = [NSDate date];

        // NSNumber
        NSDate* st2 = [NSDate date];
        
        for (int i = 0; TEST_COUNT > i; ++ i) {
            str = [[NSNumber numberWithInt:i] stringValue];
        }
        
        NSDate* ed2 = [NSDate date];
        
        // 結果表示
        NSTimeInterval span1 = [ed1 timeIntervalSinceDate:st1];
        NSTimeInterval span2 = [ed2 timeIntervalSinceDate:st2];
        NSLog(@"Format:%lf", span1);
        NSLog(@"Number:%lf", span2);
    }
}

【結果】

Format:0.220640
Number:0.316869

結構差が出ました。
私の環境では、stringWithFormatの方が高速という結果になりました。

んまあ、これは単純に、Objective-Cのメッセージ送信(他の多くの言語でいうところのメソッドコール)が1回と2回という差がそのまま出てるような気がしなくもない。

しかし、文字列と数字の連結でもないのに、書式化を使うというのは、やっぱりなんだか気持ちが悪いです。
JavaのString.valueOf(int)みたいな方が直感的だし覚えやすいと思うんですよ。


■valueOfという名のsprintf

// NSStringクラスに、valueOf(int)メソッドを追加してみた
static const int TEST_COUNT = 300000;
NSString* str;

// 良い子のみんなはこんなことしちゃダメだぞ☆
@interface NSString(Pizza)
+(NSString*)valueOf:(int)i;
@end

@implementation NSString(Pizza)

+(NSString*)valueOf:(int)i {
    char buff[32] ;
    snprintf(buff, sizeof(buff), "%d", i);
    return [NSString stringWithUTF8String:buff];
}

@end

// テスト用メイン関数
int main(int argc, const char** argv)
{
    @autoreleasepool {
        // Format
        NSDate* st1 = [NSDate date];
        
        for (int i = 0; TEST_COUNT > i; ++ i) {
            str = [NSString stringWithFormat:@"%d", i];
        }
        
        NSDate* ed1 = [NSDate date];

        // NSNumber
        NSDate* st2 = [NSDate date];
        
        for (int i = 0; TEST_COUNT > i; ++ i) {
            str = [[NSNumber numberWithInt:i] stringValue];
        }
        
        NSDate* ed2 = [NSDate date];
        
        // sprintf
        NSDate* st3 = [NSDate date];
        
        for (int i = 0; TEST_COUNT > i; ++ i) {
            str = [NSString valueOf:i];
        }
        
        NSDate* ed3 = [NSDate date];
        
        // 結果表示
        NSTimeInterval span1 = [ed1 timeIntervalSinceDate:st1];
        NSTimeInterval span2 = [ed2 timeIntervalSinceDate:st2];
        NSTimeInterval span3 = [ed3 timeIntervalSinceDate:st3];
        NSLog(@"Format:%lf", span1);
        NSLog(@"Number:%lf", span2);
        NSLog(@"sprintf:%lf", span3);
    }
}


【結果】

Format:0.220222
Number:0.313962
sprintf:0.082791


速くはなったけど、実際の開発でこんなことをするつもりはありません。
素直にNSString.stringWithFormat使います、はい。