谁在调用删除?

Posted

技术标签:

【中文标题】谁在调用删除?【英文标题】:Who is calling delete? 【发布时间】:2017-02-13 12:29:00 【问题描述】:

我遇到了这个错误:

CoreData:错误:严重的应用程序错误。捕获到异常 在调用期间从 NSFetchedResultsController 的委托 -controllerDidChangeContent:。尝试从第 0 节中删除第 0 行,但在使用 userInfo (null) 更新之前只有 0 节

我不知道是谁调用了删除操作——老实说,我只是在整个项目中没有任何删除操作。任何想法如何调试这种情况?

public func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) 
    switch(type) 
    case .insert:
        self.operation.append(BlockOperation(block: 
                                                        self.tableView?.insertRows(at: [newIndexPath!], with: .bottom)
                                                    )
        )
        // self.tableView?.scrollToRow(at: newIndexPath, at: .bottom, animated: true)
        break
    case .update:
        self.operation.append(BlockOperation(block: 
                                                        self.tableView?.reloadRows(at: [indexPath!], with: .bottom)
                                                    )
        )
        break
    default:
        break
    


public func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
    self.tableView?.beginUpdates()
    for o in self.operation 
        o.start()
    
    self.tableView?.endUpdates()


提前致谢。

更新 1

override public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell: ChannelTableCell = tableView.dequeueReusableCell(withIdentifier: "ChannelTableCell", for: indexPath) as! ChannelTableCell
    cell.setChannel(self.channelController.object(at: indexPath), delegate: self)

    return cell

更新 2

我已经简化了 didChange 方法,现在在 reloadRows() 调用时得到错误。

public func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) 
    switch(type) 
    case .insert:
        self.tableView?.insertRows(at: [newIndexPath!], with: .bottom)
        break;
    case .update:
        self.tableView?.reloadRows(at: [indexPath!], with: .bottom)
        break
    default:
        break
    

堆栈

*** First throw call stack:
(
    0   CoreFoundation                      0x0000000109db2d4b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x00000001089cb21e objc_exception_throw + 48
    2   CoreFoundation                      0x0000000109db6e42 +[NSException raise:format:arguments:] + 98
    3   Foundation                          0x000000010856066d -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195
    4   UIKit                               0x000000010ab1ab60 -[UITableView _endCellAnimationsWithContext:] + 6265
    5   UIKit                               0x000000010ab34f62 -[UITableView _updateRowsAtIndexPaths:updateAction:withRowAnimation:] + 331
    6   Joker                               0x00000001080335ac _TFC5Joker17AirViewController10controllerfTGCSo26NSFetchedResultsControllerPSo20NSFetchRequestResult__9didChangeP_2atGSqV10Foundation9IndexPath_3forOSC26NSFetchedResultsChangeType12newIndexPathGSqS4___T_ + 860
    7   Joker                               0x0000000108033740 _TToFC5Joker17AirViewController10controllerfTGCSo26NSFetchedResultsControllerPSo20NSFetchRequestResult__9didChangeP_2atGSqV10Foundation9IndexPath_3forOSC26NSFetchedResultsChangeType12newIndexPathGSqS4___T_ + 256
    8   CoreData                            0x0000000109a25400 __82-[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:]_block_invoke + 6608
    9   CoreData                            0x00000001098fa9a7 developerSubmittedBlockToNSManagedObjectContextPerform + 199
    10  CoreData                            0x00000001098fa85f -[NSManagedObjectContext performBlockAndWait:] + 255
    11  CoreData                            0x0000000109a23a17 -[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:] + 119
    12  CoreFoundation                      0x0000000109d505ec __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    13  CoreFoundation                      0x0000000109d504eb _CFXRegistrationPost + 427
    14  CoreFoundation                      0x0000000109d50252 ___CFXNotificationPost_block_invoke + 50
    15  CoreFoundation                      0x0000000109d13282 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 2018
    16  CoreFoundation                      0x0000000109d1231b _CFXNotificationPost + 667
    17  Foundation                          0x000000010849181b -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
    18  CoreData                            0x00000001098e2d90 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 704
    19  CoreData                            0x0000000109979a91 -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:deletions:updates:refreshes:deferrals:wasMerge:] + 1713
    20  CoreData                            0x00000001098dcb32 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 3554
    21  CoreData                            0x00000001098b5764 -[NSManagedObjectContext executeFetchRequest:error:] + 420
    22  libswiftCoreData.dylib              0x000000010c769e78 _TFE8CoreDataCSo22NSManagedObjectContext5fetchuRxSo20NSFetchRequestResultrfzGCSo14NSFetchRequestx_GSax_ + 56
    ...
)

【问题讨论】:

不相关:在表格视图中使用块操作有什么好处? 它与 CoreData 无关,它与插入行错误或空插入行的 TableView 有关,请发布 cellForRow 方法以获取更多信息。 嗯,@vadian,为什么不呢?这就是我用来实现自动更新的方式。好用吗? 这太过分了。它仅对集合视图有用,对表格视图无效。看看 Apple 如何实现委托方法。 Swift 中不需要break。默认情况下,这些案例不会失败。 @CodeChanger 已发布。我在那里设置了一个断点——没有人调用 【参考方案1】:

问题的直接原因是您使用 indexPath 进行行更新,而您应该使用 newIndexPath

原因是indexPath任何插入或删除之前的索引,newIndexPath之后插入和删除的索引。

如果您想从 fetchedResultsController 更新 tableView 或 collectionView 并使其从不崩溃,您可以这样做: 有 5 个可变对象 - rowInsert、rowDelete、rowUpdate、sectionInsert、sectionDelete。 rowInsert、rowDelete 和 rowUpdate 是 indexPaths 的可变数组(即NSMutableArray&lt;NSIndexPath*&gt;*)。 sectionInsert 和sectionDelete 是可变索引集(即NSMutableIndexSet*)。在controllerWillChangeContent 中清除数组。在每次更改时添加适当的 indexPath。插入和更新使用newIndexPath,删除使用indexPath,移动添加newIndexPath 到rowInsert 和indexPath 到rowDelete。在controllerDidChangeContent 中对 rowInsert 和 sectionInsert 进行升序排序,对 sectionDelete 和 rowDelete 进行降序排序。 (您可以按任何顺序保留 rowUpdate。)现在按以下顺序应用更改:rowDelete、sectionDelete、sectionInsert、rowInsert、rowUpdate。

【讨论】:

以上是关于谁在调用删除?的主要内容,如果未能解决你的问题,请参考以下文章

谁在调用错误视图,为啥?

找出谁在调用方法

谁在驱动程序代码中调用“探针”功能?

谁在 Linux 系统中调用了我的 DBus API

PHP:触发致命错误?

Python - 在特定字符串的第一个实例之后删除文本并使用不同的字符串再次执行