UITABLEVIEW Fatal error: Unexpectedly found nil while unwrapping an Optional value: when Core Data object is updated

UITABLEVIEW Fatal error: Unexpectedly found nil while unwrapping an Optional value: when Core Data object is updated

我有一个主视图应用程序,其中存储事件和事件下的一些子事件...当我添加子事件时,我最多可以添加 4 个子事件而不会导致应用程序崩溃,但是一旦我添加第 5 个事件,应用程序就会崩溃给出以下错误

Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/mike/EventTracker/Controller/DetailViewController.swift, line 303
2020-06-05 23:15:17.030027+0530 Progress Tracker[66453:2131961] Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/mike/EventTracker/Controller/DetailViewController.swift, line 303
(lldb) 

这是更新代码

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
        switch type {
        case .insert:
            table.insertRows(at: [newIndexPath!], with: .fade)
        case .delete:
            table.deleteRows(at: [indexPath!], with: .fade)
        case .update:
            configureTable(table.cellForRow(at: indexPath!)! as! SubEventDetailCell, withEvent: anObject as! SubEvent, index: indexPath!.row)
        case .move:
            configureTable(table.cellForRow(at: indexPath!)! as! SubEventDetailCell, withEvent: anObject as! SubEvent, index: indexPath!.row)
        default:
            return
        }
        configureView()
    }

configureTable 方法创建单元格的新实例并更新标签

func configureTable(_ cell: UITableViewCell, withEvent task: Task, index: Int) {
        let tableCell = cell as! SubEventDetailCell;
        tableCell.initCell(name: task.name ?? "", endDate: task.endDate ?? Date(), notes: task.notes ?? "" , taskNumber: index + 1 )
    }

我在第一次查看详细信息时收到此警告消息

Warning once only: UITableView was told to layout its visible cells and other contents without being in the view hierarchy (the table view or one of its superviews has not been added to a window). This may cause bugs by forcing views inside the table view to load and perform layout without accurate information (e.g. table view bounds, trait collection, layout margins, safe area insets, etc), and will also cause unnecessary performance overhead due to extra layout passes. Make a symbolic breakpoint at UITableViewAlertForLayoutOutsideViewHierarchy to catch this in the debugger and see what caused this to occur, so you can avoid this action altogether if possible, or defer it until the table view has been added to a window. Table view: <UITableView: 0x7fa373859a00; frame = (0 416; 991 608); clipsToBounds = YES; hidden = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x600003c9b690>; layer = <CALayer: 0x6000032cb520>; contentOffset: {0, 0}; contentSize: {991, 0}; adjustedContentInset: {0, 0, 20, 0}; dataSource: <EventTracker.DetailViewController: 0x7fa3760075d0>>

这段代码工作正常,直到我添加了 4 个子事件,但是从第 5 个之后应用程序保持 crashing.Is 无论如何我可以解决这个问题?

更新:我在 table 视图中手动将行高设置为 200,我 运行 通过将其更改为 20 进行了测试,然后我能够继续添加子事件,但是当我这样做是因为细节显示不正确

 let nibName = UINib(nibName: "SubEventDetailCell", bundle: nil)
        table.register(nibName, forCellReuseIdentifier: "TaskCell")
        table.rowHeight = 200.00 // This was changed to 20

更新:我对代码进行了一些修改并更新了这部分

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
        switch type {
        case .insert:
            table.insertRows(at: [newIndexPath!], with: .fade)
        case .delete:
            table.deleteRows(at: [indexPath!], with: .fade)
        case .update:
            table.reloadData() // this was the change
        case .move:
            configureTable(table.cellForRow(at: indexPath!)! as! SubEventDetailCell, withEvent: anObject as! SubEvent, index: indexPath!.row)
        default:
            return
        }
        configureView()
    }

这对我来说有点修复了,这是一个好的解决方案吗,我可以保持这种状态吗?或者有更好的方法吗

从不 从 table 视图强制展开中检索单元格。不要那样做。请注意,此时单元格可能不在屏幕上。

最可靠的方法是在委托方法中只调用 insert/delete/reload 行的方法

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {

    switch type {
        case .insert: tableView.insertRows(at: [newIndexPath!], with: .automatic)
        case .delete: tableView.deleteRows(at: [indexPath!], with: .fade)
        case .update: tableView.reloadRows(at: [indexPath!], with: .none)
        case .move: 
          tableView.deleteRows(at: [indexPath!], with: .automatic)
          tableView.insertRows(at: [newIndexPath!], with: .fade)
    }
}

并在其他地方处理 配置 例如在 cellForRowAt