その他
    ホーム 技術発信 DoRuby copyとretain

    copyとretain

    この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

    Objective-CのNSStringなポインタ変数をcopyしても、メモリに新しく領域が確保されるわけではなく、同じアドレスを指し示すという事を聞いたので、本当なのか調べてみた。比較の為、NSMutableStringも。

    #import <Foundation/Foundation.h>

    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

        NSString *foo = @”Hello”;
        NSString *copiedFoo = [foo copy];
        NSString *retainedFoo = [foo retain];

        NSMutableString *bar = [NSMutableString stringWithString:@”World”];
        NSMutableString *copiedBar = [bar copy];
        NSMutableString *retainedBar = [bar retain];

        NSLog(@”foo     : %@ (%x, %@, %d)”, foo, foo, [foo className], [foo retainCount]);
        NSLog(@”Copied  : %@ (%x, %@, %d)”, copiedFoo, copiedFoo, [copiedFoo className], [copiedFoo retainCount]);
        NSLog(@”Retained: %@ (%x, %@, %d)”, retainedFoo, retainedFoo, [retainedFoo className], [copiedFoo retainCount]);

        NSLog(@”bar     : %@ (%x, %@, %d)”, bar, bar, [bar className], [bar retainCount]);
        NSLog(@”Copied  : %@ (%x, %@, %d)”, copiedBar, copiedBar, [copiedBar className], [copiedBar retainCount]);
        NSLog(@”Retained: %@ (%x, %@, %d)”, retainedBar, retainedBar, [retainedBar className], [retainedBar retainCount]);

        [pool drain];
        return 0;
    }

    その結果、確かに同じだった。以下は、NSLogでコンソールに出力している内容で、括弧の中身は、左から順にアドレス、クラス名、リテインカウンタになります。

    HelloWorld[2106:10b] foo     : Hello (2030, NSCFString, 2147483647)
    HelloWorld[2106:10b] Copied  : Hello (2030, NSCFString, 2147483647)
    HelloWorld[2106:10b] Retained: Hello (2030, NSCFString, 2147483647)
    HelloWorld[2106:10b] bar     : World (105990, NSCFString, 2)
    HelloWorld[2106:10b] Copied  : World (105a00, NSCFString, 1)
    HelloWorld[2106:10b] Retained: World (105990, NSCFString, 2)

    NSStringは、後から中身を変更するわけではないので、copyしても、retainと同じなんだなと。逆にNSMutableStringは、後からappendStringなどするのでcopyした場合は、きちんと別にメモリが確保されていますね。

    ちなみに、

        NSMutableString *bar = @”World”;
        [bar appendString:@”hooo”];

    とすると、ビルドはできますが実行時に落ちてしまいます。理由は、

    *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘Attempt to mutate immutable object with appendString:’

    と、NSMutableStringと宣言したポインタ変数に文字列を代入すると、NSStringになってしまうから。

    記事を共有