当 tableView 仍在滚动时 popToRootViewController 崩溃

Yok*_*oko 5 objective-c uitableview uiscrollview ios

当我很好地滑动我的 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];
}
Run Code Online (Sandbox Code Playgroud)

那没有用,同样的崩溃。我不明白为什么,我得到的错误如下:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
Run Code Online (Sandbox Code Playgroud)

所以这意味着当一切都已经被释放时,tableView 仍在请求一个单元格。没有意义。然后我尝试了这个:

- (void) closeViewController
{
    [self.navigationController popToRootViewControllerAnimated:YES];
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)dealloc
{
    sellersTableView.dataSource = nil;
    sellersTableView.delegate = nil;
    sellersTableView = nil;
}
Run Code Online (Sandbox Code Playgroud)

给我同样的错误。有任何想法吗?

更新: 我的委托方法

创建

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];
    }
Run Code Online (Sandbox Code Playgroud)

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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

去除

- (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;
}
Run Code Online (Sandbox Code Playgroud)

解决方案 显然,将dataSource = nildelegate = nil放入textFieldDidEndEditing解决了问题。谢谢大家的回答!

tik*_*hop 3

这是 UITableView 的奇怪行为。解决此问题的最简单方法只需在调用 function 之前将dataSourcedelegate属性设置为 nil 。此外,您可以使用更常见的解决方案,并将将属性设置为 nil 的代码添加到方法中。另外你不需要这个方法。UITAbleViewpopToRootViewControllerAnimated-dealloc-killScroll

经过短暂的研究后,我意识到问题所在。这种不寻常的行为出现在 iOS 7 中。在委托被释放后,其父视图保留的滚动视图可能会向委托发送消息。它是由于-removeFromSuperview实现UIScrollView触发器而发生的-setContentOffset:,并最终向委托发送消息。