ぶろぐ

日記です

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()で処理する認識なのですが、別にやり方がある場合は教えて欲しいです><

追記

そうそう、牛丼屋でカツカレー食べながら思ったけど、クラスメソッドにしてしまえばインスタンス化する必要がない気がするけどどうなんだろう。