UIViewControllerのデリゲートが呼ばれないのには訳がある

ビューが表示される際にSettingsをロード、ビューが消える際にSettingsをセーブすれば良いはずだが、FooViewControllerに配置されているbtnBack(UIBarButtonItem)がタップされてdismissModalViewControllerAnimated:が呼ばれた際にviewDidDisappearは呼ばれないのである。

昨日のエントリを書いた後、親クラスのデリゲートメッセージを呼び出していないことをコメントで指摘頂いた時にピンと来たのだが、これは呼び出し側のViewControllerと呼び出される側のViewControllerが正しく連携していないことが原因だ。

呼び出す側、ルートのViewControllerを"A"、呼び出される側のViewControllerを"B"としよう。アプリケーション起動後にAを表示して、その後AからBを呼び出して表示、その後Bを閉じた場合の表示、非表示デリゲートの実行順は以下のようになる。

ViewController A ViewController B
viewWillAppear -
viewDidAppear -
presentModalViewController -
viewWillDisappear -
- viewWillAppear
- viewDidAppear
viewDidDisappear -
- dismissModalViewController
- viewWillDisappear
viewWillAppear -
viewDidAppear -
- viewDidDisappear

この順を見ればViewControllerの表示/非表示が一つで完結せず、遷移元と先で初めて完結するようになっていることが分かるだろう。
このときに、元->先 先->元と制御を戻しているのが親クラスのメソッドであり、これを忘れると上記のデリゲートのシーケンスが崩れてしまうのである。

ViewControllerのライフサイクルに関するデリゲートメッセージを使用する場合は、親クラスのメッセージを忘れずに呼び出さないと駄目だと言うことだ。コメントで頂いた通りこれはCocoa Touch/UIKitの基本だが、その基本すら私はまだ理解していなかったのである。恥ずかしい話だ。