Delegateインスタンス迷子事件
_人人人人人人人人人_
>EXC_BAD_ACCESS <
 ̄^Y^Y^Y^Y^Y^Y^Y ̄
でたぁぁぁぁぁああああ!!!!!1
(椅子から転げ落ちる)
アプリが落ちる
UITabBarControllerから複数のUINavigationControllerが派生しているような画面をStoryboardで作っていた。「画面が表示される前」に処理を入れたかったので、willShowViewController()を自分自身のViewControllerに実装した。
だがしかしそれはよろしくない様子。TabBarで、画面を切り替えようとしたにDelegateを呼ぼうとすると、呼びたいDelegateメソッドを実装している「(その画面の)自分自身のインスタンス」さんが開放されていることがある。するとEXC_BAD_ACCESSが発生してアプリが落ちる。(ぬるぽみたいなものだと思ってる)
あまりデバッガ使いこなしていないので、山勘デバッグとGoogle先生の情報収集の結果そういうことだと予測した。
対処
原因はそれだとにらんだので、UINavigationViewControllerDelegateをシングルトンで持たせてみんなそれを呼びにいけばいい。と思った。
うわDelegate先のメソッドで、ViewControllerで宣言しているメソッドとか使えないじゃんおわた、と思ったのですが、willShowViewControllerって今から呼びだそうとしているViewControllerのインスタンスを引数でもらってきてくれてる。賢い。これがDelegateか…。なので、ViewControllerのインスタンスを、キャストしてメソッドをコールしたら普通に使えた。
各ViewControllerではviewDidLoadに
self.navigationController.delegate = [UINavDelegate sharedUINavDelegate];
を書いてる。
// // UINavDelegate.m #import "UINavDelegate.h" #import "TopViewController.h" #import "RankingViewController.h" #import "RankingDetailViewController.h" @implementation UINavDelegate static UINavDelegate *_uiNavDelegateInstance = nil; +(UINavDelegate*)sharedUINavDelegate { @synchronized(self) { if (!_uiNavDelegateInstance) { _uiNavDelegateInstance = [[self alloc] init]; } } return _uiNavDelegateInstance; } - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { NSLog(@"TopViewConroller:: title= %@",viewController.title); // TopViewControllerのNavなら処理する if ([viewController.title isEqualToString: @"top"]) { NSLog(@"viewConrollerTitle = %@",viewController.title); TopViewController *vc =(TopViewController*) viewController; [vc sendRequest]; // RankingViewControllerのNavなら処理する } else if ([viewController.title isEqualToString: @"ranking"]) { NSLog(@"viewConrollerTitle = %@",viewController.title); RankingViewController *vc =(RankingViewController*) viewController; [vc sendRequest]; // RankingDetailViewControllerなら処理する } else if ([viewController.title isEqualToString: @"rankingDetail"]) { NSLog(@"viewConrollerTitle = %@",viewController.title); RankingDetailViewController *vc =(RankingDetailViewController*) viewController; [vc sendRequest]; } [viewController viewWillAppear:animated]; } @end
思いつきで書いたし、他にどういうやり方が主流なのかわからないけど、一応動いたのでメモ。
TableViewの内容を更新したい場合、willShowViewController()で処理する認識なのですが、別にやり方がある場合は教えて欲しいです><