从 UITableView 中删除最后一行 - 因 NSInternalInconsistencyError 而崩溃

Posted

技术标签:

【中文标题】从 UITableView 中删除最后一行 - 因 NSInternalInconsistencyError 而崩溃【英文标题】:Deleting last row from UITableView - Crash with NSInternalInconsistencyError 【发布时间】:2016-02-06 12:35:52 【问题描述】:

我尝试了所有可搜索的解决方案均无济于事。我目前的删除代码如下:

[self.conversationsTableView beginUpdates];
[_conversations removeObjectAtIndex:[indexPath row]];
if ([self.conversationsTableView numberOfRowsInSection:indexPath.section] == 1) 
    [self.conversationsTableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationAutomatic];
 else 
    [self.conversationsTableView deleteRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationAutomatic];

[self.conversationsTableView endUpdates];

如您所见,在删除部分/行之前,我在 _conversations 中正确地从我的数据源中删除 - 如果它是最后一个部分,我也会删除该部分。

我仍然遇到崩溃:

由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“UITableView 内部错误:无法生成旧节数:1 和新节数:0 的新节图”

我没有想法,除非我做了一个非常老套的解决方案,在我的实际内容上方插入一个不可见的部分,我真的不想这样做。非常感谢任何帮助。

这是我的 numberOfSectionsInTableView 的样子:

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

非常奇怪的更新:我尝试通过在删除旧部分时插入空白部分来解决此问题。但是由于某些无法解释的原因,我仍然收到错误消息。该错误坚持认为 tableview 的新部分计数为 0,即使我已将代码更改为以下内容:

if ([self.conversationsTableView numberOfRowsInSection:indexPath.row] == 1) 
    [self.conversationsTableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.conversationsTableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
 else 
    [self.conversationsTableView deleteRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationAutomatic];

现在完全不知道为什么会发生这种情况......

堆栈跟踪:

NSInternalInconsistencyException', reason: 'UITableView internal bug: unable to generate a new section map with old section count: 1 and new section count: 0'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010b6bee65 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010b137deb objc_exception_throw + 48
    2   CoreFoundation                      0x000000010b6becca +[NSException raise:format:arguments:] + 106
    3   Foundation                          0x000000010ad844de -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 198
    4   UIKit                               0x0000000109bef679 -[_UITableViewUpdateSupport(Private) _computeSectionUpdates] + 2858
    5   UIKit                               0x0000000109c00059 -[_UITableViewUpdateSupport initWithTableView:updateItems:oldRowData:newRowData:oldRowRange:newRowRange:context:] + 435
    6   UIKit                               0x00000001098cf912 -[UITableView _endCellAnimationsWithContext:] + 12936
    7   WontBuyios                          0x000000010819dea8 -[WOBMessagesViewController queryControllerDidChangeContent:] + 88
    8   LayerKit                            0x0000000108db4ca6 __65-[LYRQueryController updateWithObjectIdentifiers:changedObjects:]_block_invoke154 + 74
    9   libdispatch.dylib                   0x000000010c05249b _dispatch_client_callout + 8
    10  libdispatch.dylib                   0x000000010c03bc3c _dispatch_barrier_sync_f_slow_invoke + 284
    11  libdispatch.dylib                   0x000000010c05249b _dispatch_client_callout + 8
    12  libdispatch.dylib                   0x000000010c03a2af _dispatch_main_queue_callback_4CF + 1738
    13  CoreFoundation                      0x000000010b61ed09 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    14  CoreFoundation                      0x000000010b5e02c9 __CFRunLoopRun + 2073
    15  CoreFoundation                      0x000000010b5df828 CFRunLoopRunSpecific + 488
    16  GraphicsServices                    0x000000010e33cad2 GSEventRunModal + 161
    17  UIKit                               0x00000001097a4610 UIApplicationMain + 171
    18  WontBuyIOS                          0x00000001081a6bcf main + 111
    19  libdyld.dylib                       0x000000010c08692d start + 1
    20  ???                                 0x0000000000000001 0x0 + 1
 )

插入/删除代码:

- (void)queryController:(LYRQueryController *)controller
        didChangeObject:(id)object
            atIndexPath:(NSIndexPath *)indexPath
          forChangeType:(LYRQueryControllerChangeType)type
           newIndexPath:(NSIndexPath *)newIndexPath

    switch (type) 
        case LYRQueryControllerChangeTypeInsert: 
            [_conversations addObject:object];
            [self.conversationsTableView insertRowsAtIndexPaths:@[ newIndexPath ] withRowAnimation:UITableViewRowAnimationAutomatic];
        
            break;
        case LYRQueryControllerChangeTypeDelete: 
            [_conversations removeObjectAtIndex:indexPath.row];
            if ([self.conversationsTableView numberOfRowsInSection:indexPath.row] == 1) 
                [self.conversationsTableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
                [self.conversationsTableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
             else 
                [self.conversationsTableView deleteRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationAutomatic];
            
            break;
        
        default:
            break;
    

【问题讨论】:

如果您要从表中删除一个部分,您需要更新数据源数据,以便numberOfSections 现在将返回一个更少的部分。 【参考方案1】:

numberOfRowsInSection 呼叫_conversations.count。删除数据源数组中的项目后,它返回错误值。比较0而不是1

单个插入/删除/移动操作不需要beginUpdates / endUpdates

【讨论】:

不幸的是,这并没有解决它 - 你的逻辑是合理的,但由于某种原因,UITableView 将缓存 numberOfRowsInSection 的值。所以我仍然需要与 1 进行比较。无论如何,对 deleteSections 的调用肯定会被断点调用以确认 - 它仍然给我带来不一致的错误。【参考方案2】:

我认为@rmaddy 是对的,您应该更新numberOfSections 数据源并少返回1 个部分。 你有没有试过打电话给[tableView reloadData]

【讨论】:

我已经尝试过了 - 如果我的数据源中有对象,我有 numberOfSections 返回 1,如果没有,则返回 0。我不想使用 reloadData 因为我想保留动画。 设置为1后是否仍然显示相同的错误 您可以尝试添加检查以确保 tableView 中至少有 2 个部分,然后再删除一个部分,然后如果只剩下 1 个部分,则删除剩下的行而不是删除部分。 我只在我的 tableView 中使用了一个部分。此外,无论我是否有一个部分,如果我调用 deleteSection 或 deleteRows,我都会得到完全相同的错误。 好吧,如果你只使用一个部分,就在你删除旧部分之前,在表格中添加一个新部分,然后删除旧部分【参考方案3】:

看起来调用numberOfRowsInSection: 有副作用。在您的if 条件中使用_conversations.count。这应该可以解决您的第一个原始问题。

【讨论】:

【参考方案4】:

您正在调用 [self.conversationsTableView numberOfRowsInSection:indexPath.row] 并传入 indexPath.row。这是不正确的,应该是[indexPath section]

【讨论】:

【参考方案5】:

这最终是另一个使用 queryController 的视图控制器的问题。通过确保正确删除行来修复该视图控制器后,错误消失了。

【讨论】:

以上是关于从 UITableView 中删除最后一行 - 因 NSInternalInconsistencyError 而崩溃的主要内容,如果未能解决你的问题,请参考以下文章

从部分移动最后一行时如何删除部分标题

删除 UITableView 中的行时出错

从 tableview 部分删除最后一行时,iOS 应用程序崩溃

Swift 3.0 无法从 UITableView 中删除一行

从 UItableview 删除一行时崩溃

如何从 UITableView 中删除一行