使用 NSFetchedResultsController 更新部分

Updating sections with NSFetchedResultsController

我有一个名为 ToDoItem 的实体。其中具有三个属性:

@NSManaged var toDoString: String?
@NSManaged var creationDate: NSDate?
@NSManaged var isComplete: NSNumber?

我正在尝试创建一个 NSFetchedResultsController,它将根据 isComplete 变量显示为两个部分。我能够成功购买这样做:

lazy var fetchedResultsController: NSFetchedResultsController = {

    let questionAnswerFetchRequest = NSFetchRequest(entityName: "ToDoItem")

    let questionAnswerFetchSortDescriptor = NSSortDescriptor(key: "creationDate", ascending: false)
    questionAnswerFetchRequest.sortDescriptors = [questionAnswerFetchSortDescriptor]

    let frc = NSFetchedResultsController(
        fetchRequest: questionAnswerFetchRequest,
        managedObjectContext: (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext,
        sectionNameKeyPath:"isComplete",
        cacheName: nil)

    frc.delegate = self
    return frc
}()

我也实现了这样的删除方法:

//
// MARK: Fetched Results Controller Delegate Methods
//
func controllerWillChangeContent(controller: NSFetchedResultsController) {
    tableView.beginUpdates()
}

func controllerDidChangeContent(controller: NSFetchedResultsController) {
    tableView.endUpdates()
}

func controller(controller: NSFetchedResultsController,
                didChange sectionInfo: NSFetchedResultsSectionInfo,
                          atSectionIndex sectionIndex: Int,
                                         for type: NSFetchedResultsChangeType) {

    switch (type) {
    case .Insert:
        self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
        break
    case .Delete:
        self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
        break
    default:
        break
    }

}

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
    switch (type) {
    case .Insert:
        if let indexPath = newIndexPath {
            tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
        }
        break;
    case .Delete:
        if let indexPath = indexPath {
            tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
        }
        break;
    case .Update:
        if let indexPath = indexPath {
            tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
        }
        break;
    case .Move:
        if let indexPath = indexPath {
            tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
        }

        if let newIndexPath = newIndexPath {
            tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
        }
        break;
    }
}

问题是当我更新 isComplete 属性 时出现此错误:

CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of sections. The number of sections contained in the table view after the update (1) must be equal to the number of sections contained in the table view before the update (0), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted). with userInfo (null)

我明白这是在说什么,我只是不明白为什么它会导致那个错误。我已经根据文档实现了委托方法......


我已经更新了我的 NSFetchedResultsController 创建以根据 @wain 的回答添加另一个 sortDescriptor ,如下所示:

lazy var fetchedResultsController: NSFetchedResultsController = {

        let questionAnswerFetchRequest = NSFetchRequest(entityName: "ToDoItem")

        let isCompleteSortDescriptor   = NSSortDescriptor(key: "isComplete", ascending: false)
        let creationDateSortDescriptor = NSSortDescriptor(key: "creationDate", ascending: false)

        questionAnswerFetchRequest.sortDescriptors = [isCompleteSortDescriptor, creationDateSortDescriptor]

        let frc = NSFetchedResultsController(
            fetchRequest: questionAnswerFetchRequest,
            managedObjectContext: (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext,
            sectionNameKeyPath:"isComplete",
            cacheName: nil)

        frc.delegate = self
        return frc
    }()

我已经添加了一些断点,结果这个委托方法从未被调用:

func controller(controller: NSFetchedResultsController,
                didChange sectionInfo: NSFetchedResultsSectionInfo,
                          atSectionIndex sectionIndex: Int,
                                         for type: NSFetchedResultsChangeType) {

    switch (type) {
    case .Insert:
        self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
        break
    case .Delete:
        self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
        break
    default:
        break
    }
}

导致与上面发布的错误相同的错误。关于为什么永远不会调用它的任何想法?

您需要为 isComplete 添加排序描述符。它应该是第一个排序描述符,然后是你的日期。

基本上,排序和部分需要兼容,而您目前不兼容。