UIViewControllerのデリゲートは必ず呼ばれるとは限らない?
UIViewControllerクラスにはViewのライフサイクルに関わるデリゲートが用意されており、初期処理や終了処理などの用途に恐らく最も使うデリゲートだと思うが、ViewControllerクラスの呼ばれる経緯によっては呼ばれないケースがあるようだ。
私の現在開発しているアプリケーションでは、その設定値settings(接続先サーバのURL、音声On/Off等)をNSUserDefaultsを使ってSave/Loadしているのだが、このような処理は通常ViewControllerのデリゲートに記述するだろう。
FooViewController.m
@interface FooViewController () @property (weak, nonatomic) IBOutlet UIBarButtonItem *btnBack; @end @implementation FooViewController @synthesize btnBack; 〜 - (void)viewDidLoad { [super viewDidLoad]; //ロード時に一度だけ呼ばれる //ボタンにアクション割当 [[self btnBack] addBlockForAction: ^{ [self dismissModalViewControllerAnimated:YES]; }]; } - (void)viewDidUnload { //アンロード時に一度だけ呼ばれる [super viewDidUnload]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; //Settingsを保存 SaveSettingsTask* task = [[SaveSettingsTask alloc] init]; [task saveSettings:self viewModel:settings]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; //settingsをロード SaveSettingsTask* task = [[SaveSettingsTask alloc] init]; [task loadSettings:self viewModel:settings]; [self.tableView reloadData]; }
ビューが表示される際にSettingsをロード、ビューが消える際にSettingsをセーブすれば良いはずだが、FooViewControllerに配置されているbtnBack(UIBarButtonItem)がタップされてdismissModalViewControllerAnimated:が呼ばれた際にviewDidDisappearは呼ばれないのである。
FooViewControllerは他のUINavigationViewControllerから張られたSeque(セグエ)から遷移するのでコードは見えないのでどのような状況になっているのかが分からないのだが、これらのライフサイクルに関わるデリゲートはどんな起動の仕方でも必ず呼ばれるだと思っていたのでこれが判明した時はちょっとショックだった。
取りあえずは以下のように、dismissModalViewControllerAnimated:を呼ぶ前に明示的にviewDidDisappear:を呼び出せば来たい通りの動きになるのだが、どうも気持ちが悪いのでもう少し調べてみよう。
//ボタンにアクション割当 [[self btnBack] addBlockForAction: ^{ [self viewDidDisappear:NO]; [self dismissModalViewControllerAnimated:YES]; }];