Lifecycle of UIViewController
UIViewControllerのライフサイクルは、もうそこかしこで語り尽されてると思うけど改めて書いてみる。
基本的なライフサイクル
コンストラクタ生成から非表示になるまでは、以下のようなメソッドを通ります(ARC前提で書いています)。
init
initWithNibName:bundle:
loadView
viewDidLoad
viewWillAppear
viewDidAppear
viewWillDisappear
viewDidDisappear
dealloc
各メソッドの呼び出しタイミング
基本的には上記のような感じなんですが、実際使うときにどんなタイミングで上記の各メソッドが呼ばれるかというと、以下のようになっています。
- コンストラクタ生成(
[ViewController new]
もしくは[[ViewController alloc] init]
)
コンストラクタ生成するときは以下の順番でメソッドが呼ばれます。init
initWithNibName:bundle:
view
メソッド([vc view]
もしくはvc.view
)
vc(UIViewControllerのインスタンス)のview
メソッドを呼ぶと以下の順番でメソッドが呼ばれます。よくself.view
とか使われますが、このview
というのはそのVCにview
がなかった場合に生成するという意味もある。また、この際に呼ばれるloadView
はそのview
を生成するメソッドになります。loadView
viewDidLoad
- 表示(
pushViewController:animated:
、presentModalViewController:
)
生成されたvcを表示しようとすると以下のメソッドが呼ばれます。viewWillAppear
viewDidAppear
- 非表示(
popViewController:animated:
、dismissModalViewController:
)
逆にvcを非表示にする場合には以下のメソッドが呼ばれます。viewWillDisappear
viewDidDisappear
dealloc
この辺は覚えておくとなにかと役に立つと思うので、しっかり覚えておいた方がよさげです。
おまけ:loadViewについての注意
先程loadView
は、view
を生成するためのメソッドであると書きましたが、このメソッドを自分でオーバーライドする場合には注意が必要です。もしloadView
の中で自分でself.view
を設定するか[super loadView]
しないとその後にself.view
にアクセスする毎にloadView
が呼ばれることになり、無限ループに陥ります。
おまけ2:loadViewの使い所
自分は基本的にコントローラーのビューはInterfaceBuilderを使わずにプログラムで生成しているのですが、そのビューの生成はloadView
の中で生成することにしています。
- (void)loadView {
[super loadView];
UIView *aView = [[UIView alloc] initWithFrame:self.view.frame];
[self.view addSubview:aView];
//...
}
loadView
でビューを生成しているので、viewDidLoad
ではビューが構築されていることを前提に各種ネットワークなどの処理(APIなどにアクセスしてデータを取ってくるなど)をさせています。ちなみに各ビューの位置調整はviewWillAppear
で行なうことが多いです。
おまけ3:deallocでよくやること
ARC環境でもちゃんとdealloc
は呼ばれます。このdealloc
は非ARC環境と違って基本的には何もしないメソッドなんですが、自分の場合はここにNSLog(@"dealloc")
と書いておいたりします。
こうすると、そのコントローラーをpopなりdismissしたときにどこかで生き続けずにちゃんと破棄されているかどうかがわかるからです。循環参照とかになって破棄されずにいると、dealloc
がログに出てこないのでそれで参照が残っているのが気付けたりします。
- (void)dealloc {
NSLog(@"dealloc");
}