弹出到根视图控制器而不会导致表视图的动画崩溃

kar*_*rim 12 objective-c uikit uinavigationcontroller ios

我在标签栏控制器中有3个视图控制器.单击任何选项卡会在导航堆栈中加载其根视图控制器.

例如tab1,tab2和tab3.
导航堆栈中的第二个视图控制器(tab2VC2)有一个tableView.单击tab2,在tab2中显示VC,然后点击tab1,尝试转到rootVC.然后应用程序崩溃说

[UserDetailVC tableView:cellForRowAtIndexPath:]:发送到解除分配的实例0xe0a23b0的消息

如果我用动画popToRootVC那么没关系.我发现tab2VC2中的viewDidAppear被调用,其中tableView.reloadData被调用,然后是dealloac,似乎在此期间reloadData开始工作,表被释放.在动画的情况下,它会有一些时间,所以它不会崩溃.但没有动画,就会崩溃.你觉得,这是一个iPhone的bug吗?或者我做错了?由于pop到root控制器有一个没有动画的选项,它应该可以工作,不是吗?

#pragma mark Tab bar controller delegate
- (void)tabBarController:(UITabBarController *)tbController didSelectViewController:(UIViewController *)viewController {
    int i = tbController.selectedIndex;
    NSArray *mycontrollers = tbController.viewControllers;
    [[mycontrollers objectAtIndex:i] popToRootViewControllerAnimated:NO];
}
Run Code Online (Sandbox Code Playgroud)

Jes*_*sen 36

我认为这是一个错误,或者至少是UIKit的一个弱点,但我已经把它的一半时间都吹了,所以我不打算用示例代码编写它并立即报告给Apple.如果其他人想这样做,我将不胜感激.

这就是我认为在幕后发生的事情.你有一个UITableViewController,让我们在UINavigationController的堆栈上调用它myTable,并且导航堆栈是隐藏的,因为它位于未选择的选项卡或其他任何位置.然后,你调用[myTable.tableView reloadData],并且通过不立即重新加载数据来巧妙地优化iOS ,因为如果它在隐藏的选项卡上,用户将无法看到它.相反,重新加载请求被延迟并存储在显示视图的某处.但在显示之前,您可以将myTable从导航堆栈中弹出.当myTable的原始选项卡显示时,重载请求会被执行,但是它的dataSource不再存在,所以这是一个糟糕的访问.

现在,我使用UITableViewController的子类进行测试,该子类使用自动提供的tableView属性(不是从NIB文件加载),当myTable如上面的情况解除分配时,UITableView不会被释放.这没关系,除了UITableViewController的默认dealloc实现没有清除UITableView的dataSource属性(由init的默认实现设置).

所以,可能有一些很好的解决方法,比如自己将请求推迟到reloadData,但我能想到的最简单的方法是将它放在UITableViewController子类的实现中:

- (void)dealloc {
  ...
  self.tableView.delegate = nil;
  self.tableView.dataSource = nil;
  [super dealloc];
}
Run Code Online (Sandbox Code Playgroud)

任何额外的智慧都会受到欢迎.