LoginSignup
7
6

More than 5 years have passed since last update.

popToRootViewControllerAnimated:NOでEXC_BAD_ACCESSの事例

Last updated at Posted at 2012-12-15

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

- (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:内で参照していたメンバ変数が、popTo…によって既に破棄されていたで落ちているっぽい。

修正:
popToRootViewControllerAnimatedをdelay付きで実行

- (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に値を入れなければ発生しない

EBSelectViewController.h
#import <UIKit/UIKit.h>

@interface EBSelectViewController : UIViewController<UITableViewDataSource, UITableViewDelegate> {
    NSUInteger selectedIndex;
}
@end
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
親となる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

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6