当 tableView 仍在滚动时 popToRootViewController 崩溃
Posted
技术标签:
【中文标题】当 tableView 仍在滚动时 popToRootViewController 崩溃【英文标题】:popToRootViewController crashes when tableView is still scrolling 【发布时间】:2014-09-26 13:25:34 【问题描述】:当我在 tableView 结束滚动之前很好地滑动我的 tableView 并按下“返回”按钮时,我的应用程序崩溃了。我尝试了以下方法:
- (void) closeViewController
[self killScroll];
[self.navigationController popToRootViewControllerAnimated:YES];
[self dismissViewControllerAnimated:YES completion:nil];
- (void)killScroll
CGPoint offset = sellersTableView.contentOffset;
[sellersTableView setContentOffset:offset animated:NO];
那没用,同样的崩溃。我不明白为什么,我得到的错误如下:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
这意味着当所有内容都已被释放时,tableView 仍在请求一个单元格。没有意义。 然后我尝试了这个:
- (void) closeViewController
[self.navigationController popToRootViewControllerAnimated:YES];
[self dismissViewControllerAnimated:YES completion:nil];
- (void)dealloc
sellersTableView.dataSource = nil;
sellersTableView.delegate = nil;
sellersTableView = nil;
给我同样的错误。有什么想法吗?
更新: 我的委托方法
创作
if (textField == addSellerTextField)
sellersTableView = [[UITableView alloc] initWithFrame:CGRectMake(addSellerTextField.frame.origin.x + addSellerTextField.frame.size.width + 10, addSellerTextField.frame.origin.y - [self heightForTableView] + 35, 200, [self heightForTableView])];
sellersTableView.delegate = self;
sellersTableView.dataSource = self;
sellersTableView.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.05];
sellersTableView.separatorColor = [[UIColor grayColor] colorWithAlphaComponent:0.15];
sellersTableView.rowHeight = 44;
sellersTableView.layer.opacity = 0;
[self.companyView addSubview:sellersTableView];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^sellersTableView.layer.opacity = 1; completion:nil];
cellForRowAtIndexPath
if (tableView == sellersTableView)
if (!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.backgroundColor = [UIColor clearColor];
if ([sellersArray count] > 0)
cell.textLabel.text = [sellersArray objectAtIndex:indexPath.row];
else
UILabel *noSellersYetLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, sellersTableView.frame.size.width, [self heightForTableView])];
noSellersYetLabel.text = @"no sellers yet";
noSellersYetLabel.textAlignment = NSTextAlignmentCenter;
noSellersYetLabel.textColor = [UIColor grayColor];
[cell addSubview:noSellersYetLabel];
sellersTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
删除
- (void) textFieldDidEndEditing:(UITextField *)textField
if (textField == addSellerTextField)
[self updateSellers:textField];
- (void)updateSellers:(UITextField *)textField
[textField resignFirstResponder];
[self hideSellersTableView];
- (void)hideSellersTableView
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^sellersTableView.layer.opacity = 0; completion:nil];
sellersTableView.dataSource = nil;
sellersTableView.delegate = nil;
[sellersTableView removeFromSuperview];
sellersTableView = nil;
解决方案
所以显然将dataSource = nil
和delegate = nil
放入textFieldDidEndEditing
解决了这个问题。谢谢大家的回答!
【问题讨论】:
你能提供一些关于你的 viewController 层次结构的额外信息吗? 检查这是否可以帮助你***.com/questions/19087867/… 【参考方案1】:这是 UITableView 的奇怪行为。解决此问题的最简单方法是在调用函数popToRootViewControllerAnimated
之前将UITAbleView
的dataSource
和delegate
属性设置为nil。此外,您可以使用更常见的解决方案并将将属性设置为 nil 的代码添加到 -dealloc
方法中。另外你不需要-killScroll
方法。
经过短暂的研究,我已经意识到问题所在。这种不寻常的行为出现在 ios 7 中。其 superview 保留的滚动视图可能会在委托释放后向委托发送消息。这是由于-removeFromSuperview
实现UIScrollView
触发-setContentOffset:
并最终向委托发送消息。
【讨论】:
我尝试在关闭前将dataSource
和 'delegate` 设置为 nil,但我仍然遇到崩溃。谢谢你的信息顺便说一句:)【参考方案2】:
只需在dealloc
方法的开头添加以下行:
sellersTableView.delegate = nil;
sellersTableView.dataSource = nil;
不需要像你的 killScroll 方法那样使用 hack。
另外,我不明白您为什么要同时调用popToRootViewController
和dismissViewController
。
如果您关闭嵌入在导航控制器中的视图控制器,导航控制器本身以及所有包含的视图控制器都将被释放。
在你的情况下,你只会有奇怪的动画。
【讨论】:
试过你的方法,但它仍然因同样的错误而崩溃。关于我的popToRootViewController
和dismissViewController
,你说得对,我太傻了。
在这种情况下,请提供您的委托和数据源方法的代码。【参考方案3】:
setContentOffset
方法对你没有帮助,尝试设置
sellersTableView.dataSource = nil;
在您的 viewWillDisappear
方法中的某个位置。
这当然不是一个好习惯。
【讨论】:
试过这个,但没有运气。仍然因相同的错误而崩溃。不过谢谢!【参考方案4】:像下面这样改变你的 closeViewController 看看是否有效
(void) closeViewControllersellersTableView.dataSource = nil;
sellersTableView.delegate = nil;
[self.navigationController popToRootViewControllerAnimated:YES];
[self dismissViewControllerAnimated:YES completion:nil];
【讨论】:
感谢您的回答! Buuuuuut,试过了,结果一样。 我在想的是你没有提供 SellersTableView 与你的 xib/storyboard 的连接。【参考方案5】:我不认为将 tableView(或它的委托)设置为 nil 是问题所在。您应该能够单独执行dismissViewControllerAnimated 或popToRootViewController 而无需以这种方式修改tableView。
所以问题很可能是由于同时调用这两个方法(并且使用动画 = YES),并且这样做要求您的 viewController 设置做一些不自然的事情。
看起来在点击“关闭”按钮时,您既会弹出rootViewController
或UINavigationController
,也会关闭模态viewController
。
这样做时,您将忽略一个模态viewController
,它可能由navigationController
的topViewController
呈现(因此顶部vc 持有对模态vc 的引用)。并且您正试图通过 popToRootViewController 方法调用杀死*** vc。而且您正在使用animated = YES
完成这两件事,这意味着它们需要一些时间才能完成,并且您无法确定每件事何时完成(即您无法确定何时会调用 dealloc)。
根据您的需要,您可以做几件事中的一件。
考虑将委托属性添加到您的模态 vc。关闭模态 vc,并在模态 vc 的 completionBlock 中告诉它的委托它已经完成解散。此时调用 popToRootViewController (因为此时您可以确定模式已消失且滚动未中断)。
如果是以模态方式呈现的是您的 navController,则以相反的顺序执行此操作。通知代理弹出操作已完成,然后执行模态解除。
【讨论】:
我删除了[self dismissViewControllerAnimated:YES completion:nil];
,这是我的错误。但除此之外,错误仍然出现并使我的应用程序崩溃。谢谢你的答案!以上是关于当 tableView 仍在滚动时 popToRootViewController 崩溃的主要内容,如果未能解决你的问题,请参考以下文章
当键盘出现时,如何阻止 tableView 滚动? [复制]
为啥当我向下滚动iOS(tableView内的collectionview)时取消选择单元格?