7

在使用 NSBatchDeleteRequest 后,我​​在从 NSFetchedResultsControllerDelegate 获取准确更新时遇到问题,这些更改以更新类型而不是 didChange 委托方法上的删除类型的形式出现。有没有办法让更改作为删除进入?(我有不同的删除和更新场景)。

删除请求:(使用调用者提供的私有上下文)

fileprivate class func deletePeopleWith(ids: Set<Int>, usingContext context: NSManagedObjectContext) {

    let fr: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Person")

    var predicates: [NSPredicate] = []
    ids.forEach {

        predicates.append(NSPredicate(format: "id = %ld", $0))
    }

    fr.predicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicates)

    let dr = NSBatchDeleteRequest(fetchRequest: fr)
    dr.affectedStores = context.parent?.persistentStoreCoordinator?.persistentStores

    do {

        try context.parent?.execute(dr)
        context.parent?.refreshAllObjects()
        print("Deleting person")

    } catch let error as NSError {

        let desc = "Could not delete person with batch delete request, with error: \(error.localizedDescription)"
        debugPrint(desc)
    }

}

结果是:

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

    DispatchQueue.main.async {

        let changeDesc = "Have change with indexPath of: \(indexPath), new index path of: \(newIndexPath) for object: \(anObject)"
        var changeType = ""
        switch type {

        case .delete:
            changeType = "delete"

        case .insert:
            changeType = "insert"

        case .move:
            changeType = "move"

        case .update:
            changeType = "update"

        }

        print(changeDesc)
        print(changeType)
    }

}

印刷:

Have change with indexPath of: Optional([0, 0]), new index path of: Optional([0, 0]) for object: *my core data object*
update
4

3 回答 3

13

来自苹果的文档

批量删除比在代码中自己删除核心数据实体运行得更快,因为它们在 SQL 级别的持久存储本身中运行。作为这种差异的一部分,对持久存储进行的更改不会反映在当前内存中的对象中。

执行批量删除后,删除内存中已从持久存储中删除的所有对象。

请参阅执行后更新您的应用程序部分以处理由NSBatchDeleteRequest.

于 2016-11-14T07:39:48.827 回答
2

这是示例,对我有用。但我没有找到如何用动画更新删除,因为NSFetchedResultsControllerDelegate没有触发。

@IBAction func didPressDelete(_ sender: UIBarButtonItem) {
        let managedObjectContext = persistentContainer.viewContext
        let request = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: Record.self))
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)

        do {
            // delete on persistance store level
            try managedObjectContext.execute(deleteRequest)

            // reload the whole context
            managedObjectContext.reset()
            try self.fetchedResultsController.performFetch()
            tableV.reloadData()
        } catch {
            print("")
        }
    }

谢谢

于 2017-09-10T12:13:53.053 回答
1

由于NSBatchDeleteRequest在 persistentStore 级别(在磁盘上)删除托管对象,因此更新当前上下文(在内存中)的最有效方法是调用refreshAllObjects()上下文,如下所示:

func batchDelete() {
    if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
        let context = appDelegate.persistentContainer.viewContext
        if let request = self.fetchedResultsController.fetchRequest as? NSFetchRequest<NSFetchRequestResult> {
            let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: request)
            do {
                try context.execute(batchDeleteRequest) // performs the deletion
                appDelegate.saveContext()
                context.refreshAllObjects() // updates the fetchedResultsController
            } catch {
                print("Batch deletion failed.")
            }
        }
    }
}

无需重新获取所有对象或tableView.reloadData()

于 2020-09-23T11:22:29.567 回答