頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


配列の順番を入れ替える

頭と尻尾はくれてやる! retainCountの謎
↑ なぜretainCountを調べていたかというと、配列の順番を変えようとしてたのです。

配列はこんな感じで作ります。
NSMutableArray *strArr = [[NSMutableArray alloc] init];

NSString *s1 = [[NSString alloc] initWithString:@"apple"];
NSString *s2 = [[NSString alloc] initWithString:@"banana"];
NSString *s3 = [[NSString alloc] initWithString:@"chocolate"];
[strArr addObject:s1];
[strArr addObject:s2];
[strArr addObject:s3];
[s1 release];
[s2 release];
[s3 release];
配列を変える部分の流れはこんな感じ。
NSString *str = [strArr objectAtIndex:2];
[strArr removeObjectAtIndex:2];
[strArr insertObject:str atIndex:0];
このサンプルだと index=2の"chocolate"が先頭にやって来るはずで、実際そのように動いてくれます。

ところが、NSSting型ではない場合で不具合が出ることがあったのです。
自分で作ったクラスのオブジェクトでremoveObjectAtIndex:をした時点でdeallocが呼び出されるのです。
んんん?と思ったものの、よく考えたら上記のコードでうまくいくのも変なのでは?

冷静に一つずつ考えていくと、、、
ポインタが示す値を下のようにしてチェックすると同じ値を表示します。
NSLog(@"str pointer = %p" , str);
NSLog(@"[strArr objectAtIndex:2] pointer = %p" , [strArr objectAtIndex:2]);
つまりstrがあたかも"chocolate"って文字列を保持するように見えるけど、実際は"chocolate"って文のメモリを消費しているわけじゃなくて、そのメモリのアドレスを持っているだけだよな(これこそポインタの利点)。

とすると、 removeObjectAtIndex:の時点で配列に入っていたオブジェクト(ここでは"chocolate")はretainCountがマイナス 1されて、0になったらメモリが解放される。
だから、insertObject:str:なんてしても無駄じゃないか?

だとしたら、解決方法は以下のようになるよな。
MyClass *myClass = [[myClassArr objectAtIndex:2] retain];
[myClassArr removeObjectAtIndex:2];
[myClassArr insertObject:myClass atIndex:0];
[myClass release];
こうすることで不具合が起きないようになりました。
これが意図通りに動くのは理解できる。

ところが、 NSStringの場合はなぜかretainしなくてもいいんだよね。
まあ、NSStringのretainCountが2147483647と膨大なことを考えればretainは不要なんだろうけど。
他の型だとremoveObjectAtIndex:のところでメモリの解放が行われることがあるのに。
このあたり要注意だな、、、

<< iPhone Developer Programを購入した  TopPage  神座の還元セールは超お得! >>

コメント


管理者にだけ表示を許可する
 

トラックバック

トラックバックURL
http://ringsbell.blog117.fc2.com/tb.php/410-5299fba1




Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.

FC2Ad