アプリを作ってみて初めてreleaseの重要性を実感しました(^^;) CGContextでUITextField、UILabelを大量に追加したUIViewを往復してると、動作が重くなりメモリリーク(>_<)
UINavigationControllerでViewController(@synthesizeした)をpush後、親ページに戻った時(popした時)に、viewDidUnloadが発生しないことがわかりました。
その為、以下の遷移でを繰り返していると
(1) UIViewControllerをinitWithNibNameでallocし、UINavigationControllerに追加(pushViewController) (2) UIViewControllerのviewDidloadが呼ばれる (3) UIViewControllerに大量のオブジェクトをaddSubViewする (3) UINavigationControllerで戻る(popViewController) (4) UIViewControllerがdeallocされない
と、通常は2~3Mのメモリを行ったりきたりするのですが、ページにアクセスする毎に500K単位で増えていきました。
(1) pushするUIViewControllerを@synthesizeして(せざるを得なかった)利用していた (2) pushするUIViewControllerをpush後にreleaseしていなかった(できなかった) (3) UIViewにaddSubViewしたオブジェクトをreleaseしていなかった
pushするUIViewControllerを@synthesizeしていた(せざるを得なかった)のは、自分の設計ミス(^^;)
@synthesize hogeViewController;
...
-(void)pageHoge {
hogeViewController= [[HogeViewController alloc] initWithNibName="HogeViewController" bundle:nil];
[self.navigationController pushViewController:hogeViewController animated:YES];
}
他のメソッドでViewControllerを利用したいばかりに、不用意に@synthesizeした結果です。 HogeViewControllerに追加したオブジェクトがアクセスするたびにallocされますが、UINavigationControllerで戻ってもviewDidLoadが呼ばれません。 よって全てのオブジェクトがメモリ内に残ったままです。
-(void)pageHoge {
HogeViewController *nextController = [[HogeViewController alloc] initWithNibName="HogeViewController" bundle:nil];
[self.navigationController pushViewController:nextController animated:YES];
[nextController release];
}
それでも@synthesizeが必要なときは、nilで判断するかないのかな???
-(void)addButton {
IButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(edit:) forControlEvents:UIControlEventTouchUpInside];
[self addSubView:button];
}
単純にbuttonのrelease忘れです。
これも忘れがちですが、UIButton等を動的にaddSubViewする場合、retainされたオブジェクトにしておくことです。
-(void)addButton {
UIButton *button = [[UIButton buttonWithType:UIButtonTypeCustom] retain]; //retain
[button addTarget:self action:@selector(edit:) forControlEvents:UIControlEventTouchUpInside];
[self addSubView:button];
[button release]; //メモリ開放
}
retainしないでaddSubView後にreleaseするとアプリが落ちます。 これ外部の指摘で気づきました。 ※他にも多々そういうトピックがあるかと・・・ buttonWithType は init 系メソッドじゃないので、retain の必要ないので下記のコードで大丈夫です。
-(void)addButton {
IButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(edit:) forControlEvents:UIControlEventTouchUpInside];
[self addSubView:button];
}
まぁ、retain して release してもトータルプラマイゼロにはなると思いますが、意味がない・・・。
これらは、InstrumentsのLeaksを利用してメモリ変化が見られます。
勉強を始めた時には実感がなかったのですが、作ってみて初めて身にしみますw
メモリリーク対策のサイト ・How to avoid memory leaks in iPhone applications