TwitterでViewライフサイクルについて話題になったので、まとめてみました。
@tomohisa @gaolay @replicantnexus6 @t_okada これまではiOS5では呼ばれてましたね。5ではwillUnloadっていう使いドコロのわからないメソッドも追加されてそれも呼ばれてましたし。
— kishikawa katsumiさん (@k_katsumi) 9月 20, 2012
- シングルビューの動作
- モーダルビューが呼ばれたとき
- モーダルビュー表示中にメモリ警告が発生した場合-iOS5以前
- モーダルビュー表示中にメモリ警告が発生した場合-iOS6以後
こちらが基本となります。よく勘違いされているのは、ViewDidUnloadは、いつもViewが閉じるときに呼ばれるというものですが、これは間違いで、通常、ViewDidUnloadは呼ばれません。
モーダルビューが呼ばれたときの注意点は、裏にあるビューは、一度UIWindowから削除されて、ViewDidDisappearが走るという点ですね。もちろん、戻るときは、またViewWillAppearが再度呼ばれます。
ここで初めて、ViewDidUnloadが呼ばれました。ただ、ここでViewが削除されて、再構成されるため、メモり回りのエラーがよく発生していたと、WWDC2012 – 236のビデオでいっていました。
ViewDidUnloadが非推奨メソッドになって、呼ばれなくなりました。そのかわり、reveivedMemoryWarning関数は引き続き呼ばれているので、そこで必要なメモリの解放を行うことが出来ます。WWDCのビデオで、iOS5でも、ViewDidUnloadを呼ばないと聞いたような気がしたのですが、実際実験してみたところ、iOS5シミュレータでは、ViewDidUnloadは確かに呼ばれていました。
追記: iOS6で、iOS5と同様のビューの解放をする方法
iOS6の場合でも、ビューが多くもメモリを使用している場合、明示的にビューを解放したいときは、下記ようなのコードで行うことが出来ます。photo…の部分は各ビューの状況に合わせて下さい。
追記2: IBOutletなどの解放はどうするか
IBOutletなどの解放はどうするのかという質問があったので、その情報も少し書いておきます。
@grandeforesta Outletにnilを入れる処理ですか? iOS5以降ARCであれば、 @ property (weak) IBOutlet UILabel * labelComment; の用に書くことによって、何もする必要ないですね。
— Tomohisa Takaoka さん (@tomohisa) 9月 21, 2012
ここにあるように、ARC以後、IBOutletは、Weakで定義して挙げることにより、心配は無くなります。また、strongで定義していた場合も、そのリリースはdeallocで行われるので、明示的に解放する必要はありません。ARC無しの場合は、解放系は、deallocの中で、releaseを使って行うのがよいと思います。
この流れを理解していると、どのメソッドにどの処理を書くべきかが分かりやすくなると思います。それでも最適な処理を最適な場所に書くのは結構大変ですね。
この動作のためにテストで使用したプロジェクトをここからダウンロードできます。
ViewLivesTestプロジェクト
なにか突っ込みなどありましたら、コメント、Twitterまで教えてください。
ライフサイクルが変わったと聞いてまとめを探していました。
とても参考になりました!
– (void)loadView ; がどうなっているのかも欲しかったです。
テストプロジェクトに、LoadViewの動きもログを出すようにしてみたところ、LoadViewは、iOS5, 6変わらず、常に、ViewDidLoadの前ですね。参考になってよかったです。
今更ですがちょっと気になったのでコメントします
if ([self.view window] == nil)
これだけだと,既に self.view が nil の場合に loadView: が走るので,
if ([self isViewLoaded] && [self.view window] == nil)
とした方が良いと思います
ありがとうございます!興味深いですね。ちょっと時間あるときに検証してみます。ちなみに、ViewController Programming Guide
https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ViewControllerPGforiOS.pdf
では、
if ([self.view window] == nil)
だけのようです。