[UIKit]ViewDidLoad は一度しか呼ばれないと思っていました…

TweetOverviewのクラッシュレポートを解析して、気がつきました。

ViewDidLoadでのクラッシュ
ViewDidLoadでのクラッシュ

これは、ViewControllerのViewDidLoadメソッドが複数回呼ばれている故のクラッシュでした。

TweetOverviewでは、詳細画面から、メイン画面に戻るのですが、その際に、ViewDidLoadが再度呼ばれていました。といっても、Viewを再作成している訳ではなくて、[detailController dismissModalViewController…]から戻って来たときです。これは、どうも常識だったようですが、知りませんでした。。。昔のコード見直さないと。
iphone – When is viewDidLoad called? – Stack Overflow こちらを見ると、

You have to assume that viewDidLoad can be called multiple times. If there is a memory warning sent, your view controller will unload the view from memory, and the next time it is needed viewDidLoad will be called.

viewDidloadは、複数回呼ばれる事を予測するべきです。メモリの警告が送られると、ViewControllerは、一度viewをメモリから解放して、次にviewが必要になる時に、再度viewDidLoadを呼ぶことになります

との事です。つまり、view毎の状態を保存するなどのivarがある場合、viewDidLoad、viewDidUnloadなどでの、ivarの初期化、解放は危険だという事ですね。メモリの警告が発生される時に、バックグラウンドにあるビューがunloadされ、loadされる危険があります。はい、気をつけるとともに、昔のものを見直します。

対策方法

とはいえ、最初に表示される際のviewDidLoadは非常に便利なので、クラスのivarにdispatch_once_tで、一度だけ行うトークンを作成して、

@implementation ViewController{
dispatch_once_t onceToken;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
dispatch_once(&onceToken, ^{
tweetViews = [[NSCache alloc] init];
});
}

の用に記述して、初期化コードは、インスタンスに対して一度しか発生しない様に設定しました。

iOSのUIKitは、メモリ管理に関してもよく作られていますが、いろいろ注意点がありますね。

2012/5/15追記しました。


これからは、AwakeFromNib使います。こちらにも詳しく書いています。
cocoa touch – Which should I use, -awakeFromNib or -viewDidLoad? – Stack Overflow

Also important is that the awakeFromNib function will never be called after recovering from memory warning. But, viewDidLoad function will be called.

AwakeFromNibは、メモリ警告から復帰した時に呼ばれないけど、viewDidLoadFunctionは、呼ばれます。

描画に関係しない初期化は、AwakeFromNibが正解ですね。

「[UIKit]ViewDidLoad は一度しか呼ばれないと思っていました…」への1件のフィードバック

コメントを残す

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

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