在 UITableView 的一部分上使用 NSFetchedResultsController

Using NSFetchedResultsController on a part of UITableView

我在 UISplitViewController 中有一个 UITableViewController。这个 tableViewController 收到两个东西:

  1. 发票数组
  2. 客户对象

所以我正在做的是在 UITableView 的第一部分(或 Section 0)填充发票详细信息。

对于第二部分,我使用 NSFetchedResultsController 获取具有 invoice == nil 的客户的所有属性,并将其显示在 table 视图的第二部分。

所以基本上,只在 UITableViewController 的一部分而不是全部使用 NSFetchedResultsController

现在,一切正常。但是,当我点击第 2 部分的行时,我让用户将 property 添加到新发票中。当我这样做时,出现此错误:

CoreData: error: Serious application error.  An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:.  Invalid update: invalid number of rows in section 0.  The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)

不确定为什么会这样。我知道 fetchedResultsController 期待第 0 节,但我已确保手动强制它仅使用第 1 节。

参考代码为:

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
    switch (type) {
    case .Insert:
        if let indexPath = newIndexPath {
            let editedNewIndexPath = NSIndexPath(forRow: indexPath.row, inSection: 1)
            tableView.insertRowsAtIndexPaths([editedNewIndexPath], withRowAnimation: .Fade)
        }
        break;
    case .Delete:
        if let indexPath = indexPath {
            let editedCurrentIndexPath = NSIndexPath(forRow: indexPath.row, inSection: 1)
            tableView.deleteRowsAtIndexPaths([editedCurrentIndexPath], withRowAnimation: .Fade)
        }
        break;
    case .Update:
        if let indexPath = indexPath {
            let editedCurrentIndexPath = NSIndexPath(forRow: indexPath.row, inSection: 1)
            if let cell = tableView.cellForRowAtIndexPath(editedCurrentIndexPath){
                configureCell(cell, atIndexPath: editedCurrentIndexPath)
                //tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: .None)
            }
        }
        break;
    case .Move:
        if let indexPath = indexPath {
            let editedCurrentIndexPath = NSIndexPath(forRow: indexPath.row, inSection: 1)
            tableView.deleteRowsAtIndexPaths([editedCurrentIndexPath], withRowAnimation: .Fade)
        }

        if let newIndexPath = newIndexPath {
            let editedNewIndexPath = NSIndexPath(forRow: newIndexPath.row, inSection: 1)
            tableView.insertRowsAtIndexPaths([editedNewIndexPath], withRowAnimation: .Fade)
        }
        break;
    }
}

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 2
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if section == 0{
        if let ivData = self.invoices{
            print("Section0 - \(ivData.count)")
            return ivData.count
        }
    }
    else if section == 1{
        if let sections = fetchedResultsController.sections {
            let sectionInfo = sections[0]
            print("Section1 - \(sectionInfo.numberOfObjects)")
            if sectionInfo.numberOfObjects > 0{
                return sectionInfo.numberOfObjects
            }
            else{
                return 1
            }
        }
    }
    return 0
}

保存新发票的代码是:

do{
                    self.invoices!.append(billRecord as! InvoiceInfo)
                    try billRecord.managedObjectContext?.save()
                    try self.customer!.managedObjectContext?.save()
                    try record.managedObjectContext?.save()
                    //self.lookUpLotsWithoutBills()
                    self.tableView.reloadData()

                }
                catch{
                    self.invoices!.removeObject(ivRecord)
                    let alertController = UIAlertController(title: "Unexpected Error", message: "Your data could not be updated. Please try again later.", preferredStyle: .Alert)
                    alertController.addAction(UIAlertAction(title: "Done", style: .Cancel, handler: nil))
                    self.presentViewController(alertController, animated: true, completion: nil)
                }

这里可能有什么问题?

看起来你的 FRC 工作正常,但你的代码没有告诉 table 视图关于一个新的发票行被添加到第 0 节。目前还不清楚为什么,但我我猜是因为 FRC 在您添加发票之后但在您调用 table 上的重新加载数据之前触发更新。在那个时间点,第 0 节的行数是错误的,您还没有告诉 table。