popToRootViewControllerAnimated:NOでEXC_BAD_ACCESSの事例


現象：
テーブルビューで、行を選択後にpopToRootViewControllerAnimatetd:で親のビューコントローラに戻そうとしたらEXC_BAD_ACCESSになった。引数がNOの場合のみ発生。

```Objective-C
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSUInteger section = indexPath.section;
    NSUInteger row = indexPath.row;
	
    [tableView reloadData];
    [self.navigationController popToRootViewControllerAnimated:NO];
}
```

原因：
親のビューコントローラに戻す前に、reloadDataでセルの再描画を行なっていた（選択されたものにチェックマークをつける目的だった）。reloadDataにより呼ばれたtableView:cellForRowAtIndexPath:内<del>で参照していたメンバ変数が、popTo…によって既に破棄されていた</del>で落ちているっぽい。



修正：
popToRootViewControllerAnimatedをdelay付きで実行

```Objective-C
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSUInteger section = indexPath.section;
    NSUInteger row = indexPath.row;
	
    [tableView reloadData];
    [self performSelector:@selector(popToRoot:) withObject:nil afterDelay:0.1];

}

- (void)popToRoot:(id)sender {
    [self.navigationController popToRootViewControllerAnimated:NO];
}
```

## 追記

発生条件をもう少し調べた。以下のコードで、UITableViewのボタンを押して前に戻るのを何度か操作するとEXC_BAD_ACCESSが発生する。Xcode4.5.2 iPhone 6.0 Simulator。non ARC

わかっている条件：
- UITableViewControllerでは発生せず、UIViewControllerにUITableViewを貼りつけた場合にのみ発生
- cell.accessoryViewに値を入れなければ発生しない

```Objective-C:EBSelectViewController.h
#import <UIKit/UIKit.h>

@interface EBSelectViewController : UIViewController<UITableViewDataSource, UITableViewDelegate> {
    NSUInteger selectedIndex;
}
@end
```

```Objective-C:EBSelectViewController.m
#import "EBSelectViewController.h"

@implementation EBSelectViewController

- (void)viewDidLoad {
    UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
    tableView.dataSource = self;
    tableView.delegate = self;
    [self.view addSubview:tableView];
    [tableView release];
    
    selectedIndex = 0;
}

#pragma mark -

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 3;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    NSString *cellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
    }

    cell.textLabel.text = NSLocalizedString(@"may error", nil);
    cell.accessoryView = nil;
    if (indexPath.row == selectedIndex) {
        cell.accessoryView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"check.png"]] autorelease];
    }
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    selectedIndex = indexPath.row;
    [tableView reloadData];
    
    [self.navigationController popToRootViewControllerAnimated:NO]; //NG
//    [self.navigationController popToRootViewControllerAnimated:YES]; //OK
//    [self performSelector:@selector(delayedPopToRoot:) withObject:nil afterDelay:0.1]; //OK
}

#pragma mark -

- (void)delayedPopToRoot:(id)sender {
    [self.navigationController popToRootViewControllerAnimated:NO];
}

@end
```

```Objective-C:親となるViewController
@implementation FLViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    UIButton *naviToTestButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    naviToTestButton.frame = CGRectMake(100.0f, 50.0f, 100.0f, 44.0f);
    [naviToTestButton setTitle:@"test" forState:UIControlStateNormal];
    [naviToTestButton addTarget:self action:@selector(testButtonTaped:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:naviToTestButton];
}

- (void)testButtonTaped:(id)sender
{
    EBSelectViewController *controller = [[EBSelectViewController alloc] init];
    controller.hidesBottomBarWhenPushed = YES;
    [self.navigationController pushViewController:controller animated:YES];
    [controller release];
}
@end

```