UITableView 更新失败

Fail on UITableView update

需要你们的帮助! 我只对 iOS 9 上的错误感到生气。 正如您在下面看到的,它在 iOS 11

上进展顺利

一开始,我有 4 个状态为 "Nouveau" 的新单元格。 当我单击 "new" 单元格时,状态更改为 "En attente"(对于 "waiting")。

在 iOS9 上,直到最后一个单元格之前一切正常。当我点击最后一个 "new" 单元格时,它不会移动到 "waiting" 并且 "new" 部分仍然存在。在此之后,table 视图不再获得更新,当我切换到另一个 viewController 并返回包含 table 视图的视图时,它会恢复正常。

我正在使用 NSFetchedResultsController。数据很好,部分数量很好,按部分分类的元素数量很好,标题很好。

开头有 1 个标题为 "Nouveau" 的部分,有 4 个 objects 最后,1 个标题为 "En attente" 的部分和 4 个 objects

extension CRDashboardOrdersViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        print( self.fetchResult?.sections?.count ?? 0 )
        return self.fetchResult?.sections?.count ?? 0
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print( self.fetchResult?.sections?.get(index: section)?.numberOfObjects ?? 0 )
        return self.fetchResult?.sections?.get(index: section)?.numberOfObjects ?? 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: CRDashboardOrderTableViewCell = tableView.dequeueReusableCell(withIdentifier: "CRDashboardOrderTableViewCell") as! CRDashboardOrderTableViewCell
        let order: Order = self.fetchResult.object(at: indexPath) as! Order

        cell.order = order

        if let selectedIndexPath = self.selectedIndexPath, selectedIndexPath == indexPath {
            self.tableView.selectRow(at: selectedIndexPath, animated: false, scrollPosition: .none)
        }

        return cell
    }
}

extension CRDashboardOrdersViewController: UITableViewDelegate {
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            self.selectedIndexPath = indexPath
        }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        print( self.fetchResult?.sections?.get(index: section)?.name ?? "???" )
        return self.fetchResult?.sections?.get(index: section)?.name ?? "???"
    }
}

extension CRDashboardOrdersViewController: NSFetchedResultsControllerDelegate {
        func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
            self.tableView.beginUpdates()
        }

 func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
        print(sectionIndex)
        print(sectionInfo.indexTitle)
        switch type {
        case .insert:
            self.tableView.insertSections(IndexSet(integer: sectionIndex), with: .fade)
        case .delete:
            self.tableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
        default:
            break
        }
    }

  func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
        switch type {
        case .update:
            self.tableView.reloadRows(at: [indexPath!], with: .fade)
            if indexPath == self.selectedIndexPath {
                self.selectedIndexPath = indexPath
            }
            break
        case .insert:
            self.tableView.insertRows(at: [newIndexPath!], with: .fade)
            self.selectedIndexPath = nil
            break
        case .delete:
            self.tableView.deleteRows(at: [indexPath!], with: .fade)
            self.selectedIndexPath = nil
            break
        case .move:
            self.tableView.moveRow(at: indexPath!, to: newIndexPath!)
            if indexPath == self.selectedIndexPath {
                self.selectedIndexPath = newIndexPath
            }
            break
        }
    }

 func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        self.tableView.endUpdates()
    }
}

您的 cellForRow: 和 FetchedResults 委托有误。

当使用 FetchedResultsController 时,在 .update 上你不应该使用 reloadRows,这会导致问题,而你应该有一个像这样更新单元格模型的方法:

func updateCell(atPath indexPath: IndexPath) {
    if let cell = tableView.cellForRow(at: indexPath) as? MyCell {
        updateCell(withCell: cell, atIndexPath: indexPath)
    }
}

func updateCell(withCell cell: MyCell, atIndexPath indexPath: IndexPath) {
    if let MyModel = fetchedResultsController?.object(at: indexPath) {
        cell.model = myModel
}
}

然后在您的委托 .update 中调用 updateCell(AtIndexPath) 来更新单元格 UI。

您还应该在 cellForRow 中使用此单元格配置方法