ホーム 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になってしまうから。

記事を共有
モバイルバージョンを終了