明示的なreleaseは死亡フラグ

「あるUIViewControllerが表示されるたびに、メンバ(例えば何らかのUIViewクラスとか)を作り直したい」ということが度々あり、何となく以下のような実装をしていました。(hogeViewメンバは @retain @synthesize 指定済)

-(void)viewWillAppear:(BOOL)animated {
    self.hogeView = [[[HogeView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)] autorelease];
    [self.view addSubview:hogeView];
}

-(void)viewDidDisappear:(BOOL)animated {
    [self.hogeView release];
}

ところが上記のソースコードだと、これを指定したUIViewControllerを2回目に表示したタイミングでEXC_BAD_ACCESSが発生してしまいます。

冷静に考えてみればこれは当たり前の話で、2回目のviewDidAppearが呼ばれると、hogeViewに代入されていた古いオブジェクトのretainCountがマイナスになり死亡します。

つまり、

  • 1回目の画面が消えるタイミングで、viewDidDisapperからreleaseメソッドが呼ばれる。
  • しかし、releaseメソッドを呼んだだけでは、self.hogeView には nilオブジェクトは入らないが、retainCountは1減少して0になる。
  • 2回目の画面表示のタイミングで、self.hogeView にかつて代入されていたオブジェクトのreleaseメソッドが呼ばれる。
  • retainCountがマイナスに→


つまりはreleaseメソッドを呼んでいたのが不幸の始まり。nilを代入してあげるのが正解です。

-(void)viewDidDisappear:(BOOL)animated {
    self.hogeView = nil;
}