« NSDateFormatterとの戦い | トップページ | スカイウォーター »

2012.04.25

ARC使用時の、動的確保されたid配列の扱いについて

 今回もiOS(とかOS X)のハナシ。

 NSZoneMalloc()で動的確保されたid配列。つまりNSArrayを使わない自前の配列は、ARCではどう管理されるのか、捨てる時はnilをセットするのか、ということがわからなかったので、コードを書いて試してみた。

@interface TestObject : NSObject
{
@package
	NSInteger	_id;
}
-(id)initWithID:(NSInteger)idn;
@end
@implementation TestObject
-(id)initWithID:(NSInteger)idn { _id = idn;
return [super init]; }
-(void)dealloc { printf("%d\n",_id); }
@end
static __strong id *_alloc(NSInteger size) { size *= sizeof(id); void *p = NSZoneMalloc(NSDefaultMallocZone(),size); memset(p,0,size);
return (__strong id *)p;
}
static void _free(__strong id *p)
{
NSZoneFree(NSDefaultMallocZone(),p);
}
void ARCAllocedObjectArrayTest(void)
{
__strong id *ary = _alloc(1);
*ary = [[TestObject alloc] initWithID:1];
_free(ary);
ary = _alloc(1);
*ary = [[TestObject alloc] initWithID:2];
*ary = nil;
}

 ARCAllocedObjectArrayTest()を実行して試したところ、

2

 と出力された。つまり、nilを明示的にセットしないと何も起こらないということになる。ARCは大規模にコードをいじってretainだのreleaseだのしてくれるが、__strong id *をNSZoneFree()した時にはreleaseは入れてくれないらしい。

 今回やってみてわかったが、idを戻り値にする関数は、何もキャストしないと__autoreleaseであると見なされるようだ。確かにObjective-Cの作法ではそれが普通か。だが、.cファイル内のstatic関数は、__strongで返す事もよくある。なので今回は、__strongキャストを入れて返すようにしてみた。

 このコード内では、一旦void *に入れてゼロクリアしてから__strong idにしている。NSZoneMalloc()の戻り値を__strong id *にキャストすると、動的確保した内容が不定であった場合、最初に何かをセットする時に、不定なポインタを使ってreleaseしてしまう(その前にretainCountが-1される)のを防ぐためにこのようにした。

P.S.
 最近、このようにプログラミングの作法とかそういう事ばかり書いている。マトモな事ばかり書いてると大変恥ずかしく(笑)、頭がどうにかなりそうなので、twitterではうんこうんこと連呼(韻)させてもらいたい。

|

« NSDateFormatterとの戦い | トップページ | スカイウォーター »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: ARC使用時の、動的確保されたid配列の扱いについて:

« NSDateFormatterとの戦い | トップページ | スカイウォーター »