ios - 使用 NSFetchedResultsController 更新部分

标签 ios swift core-data 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)

虽然我理解这是在说什么,但我只是不明白为什么它会导致该错误。我已经根据文档实现了委托(delegate)方法......


我已经更新了我的 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
    }()

我添加了一些断点,结果这个委托(delegate)方法从未被调用过:

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 添加一个排序描述符。它应该是第一个排序描述符,然后是你的日期。

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

关于ios - 使用 NSFetchedResultsController 更新部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39563284/

相关文章:

iphone - ipad/iphone 应用程序的最佳方法

ios - 如何调整 UITableViewCell 中的图像大小?

ios - TableView 滚动到最后一个单元格之外

ios - 不调用didSelectRowAtIndexPath获取UITableViewCell数据

ios - 将 CKServerChangeToken 保存到核心数据

ios - UIView 在动画期间沿着 UIBezierPath 暂停

ios - 当图像保存在核心数据的 Collection View 中时,应用程序因内存错误而崩溃

ios - 在单例类中追加数组并在另一个 Controller 中计数返回 0

json - 从 Core Data 创建一个 json 文件

swift - 有什么方法可以将 Double 转换为 NSNumber 并在 Swift 中将精度保持在至少小数点后 6 位?