【iOS】 Objective-Cでの参照カウンタ問題(NSMutableArray)

iOSのプログラムを作ってて、少しトラブったので調査してみました。NSMutableArrayのオブジェクトを作成して、それをクラス内で共通オブジェクトとして使用する予定で以下のようなコードを書きました。

@interface Test : NSObject
{
    NSMutableArray* testArray;
}

– (void)addValue:(NSNumber)num;

@end

@implementation Test

– (void)init
{
    self = [super init];
    if (self) {
        testArray = [NSMutableArray array];
    }
}

– (void)addValue:(NSNumber)num
{
    [testArray addObject:num];
}

– (void)dealloc
{
    [testArray release];
    [super dealloc]
}

@end

この初期化メソッドをUIViewController派生クラスのloadViewメンバから呼び出したのですが、その後addValueメンバを呼び出した時にNSMutableArrayのaddObjectメンバでエラーになりました。調べてみると、この時点でtestArrayの参照カウンタが0に。これはつまり、オブジェクトが既に回収されてしまっている事を示します。testArrayのreleaseを呼び出していないにも関わらずです。
そこでオブジェクト生成をクラスメソッドのarrayから以下のオブジェクトメソッドに変更してみました所、参照カウンタが0にならずに正常に動作します。

testArray = [[NSMutableArray alloc] init];

さてさて何故でしょう。
調べてみたところ NSArray の array メソッドは内部で autorelease を呼び出すそうです。つまり、[NSMutableArray array]は正確には以下のコードに相当します。

testArray = [[[NSMutableArray alloc] init] autorelease];

そして、このautoreleaseが回収されるのはUIKitのコントロールクラスのイベントメソッドから戻ったタイミングのようです。つまり、loadViewメンバ処理を抜けた段階でautoreleasepoolに登録されたオブジェクトは回収されてしまっていたのでした。原因が分かれば後は修正方法ですが2通りあります。

1. ちゃんとretainする。

testArray = [NSMutableArray array];
[testArray retain];
明示的に参照カウンタをインクリメントするので、メモリ管理が厳密にできます。

2. propertyを使う。

@interface Test : NSObject
{
    NSMutableArray* testArray;
}
@property (nonatomic, retain) NSMutableArray* testArray;
@end

そしてオブジェクト生成部分を以下のようにします。

self.testArray = [NSMutableArray array];

このようにretain宣言したプロパティを使えば、プロパティに代入したタイミングで参照カウンタが+1されるので正しく動作します。

しっかし、個人的にはこのautoreleaseは嫌やなぁ。(>_<)
そもそもオブジェクトが生成された階層と別の階層で開放されるのはバグの温床になるし、オブジェクトの寿命管理が厳密にできていないのも気持ち悪い。それに、呼び出し元クラスがautoreleasepoolを使用している事が前提になるから、関数仕様にも冗長な要求が発生するしね。やはり alloc+init+release で厳密にオブジェクトの寿命管理をする方が性にあってるようです。

Author: kan
初めてプログラムらしきものを作ったのは幼稚園の時。それから約40年経ち、現在はデジタル回路設計から信号処理、機械学習まで幅広い経験を活かしてシステムアーキテクトとして活動中。超並列処理、デジタル回路とソフトウェアのバランス設計が得意分野。 Linux/Mac/Windows使い。 C/C++を主要言語として、Unity、Qtなどのフレームワーク興味あり。UI/UXデザイン、STL拡張など。 音声処理、画像処理、技術コンサルは仕事でも請け負います。 一般ソフトウェア開発プロセス、医療機器ソフトウェア開発プロセス作成も進行中。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください