【问题标题】:SwiftUI: List does not update automatically after deleting all Core Data Entity entriesSwiftUI:删除所有核心数据实体条目后列表不会自动更新
【发布时间】:2020-05-30 11:38:08
【问题描述】:

我知道 SwiftUI 使用状态驱动的渲染。所以我假设,当我删除核心数据实体条目时,我的核心数据元素列表会立即刷新。 我使用这段代码,成功清理了我的实体:

func deleteAll()
{
    let fetchRequest: NSFetchRequest<NSFetchRequestResult> = ToDoItem.fetchRequest()
    let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

    let persistentContainer = (UIApplication.shared.delegate as! AppDelegate).persistentContainer

    do {
        try persistentContainer.viewContext.execute(deleteRequest)
    } catch let error as NSError {
        print(error)
    }
}

为了让我的视图中的列表在视觉上是空的,我必须在之后离开视图(例如使用“self.presentationMode.wrappedValue.dismiss()”)并再次打开它。好像这些值仍然存储在内存中的某个地方或某处。 这当然不是用户友好的,我相信我只是监督一些立即刷新列表的东西。 也许有人可以帮忙。

【问题讨论】:

    标签: swift core-data swiftui


    【解决方案1】:

    原因是execute(如下详述——注意第一句)不影响托管对象上下文,所以所有获取的对象都保留在上下文中,UI 代表上下文真正呈现的内容。

    因此,一般而言,在此批量操作之后,您需要通知回该代码(此处未提供)强制同步并重新获取所有内容。

    API接口声明

    // Method to pass a request to the store without affecting the contents of the managed object context.
    // Will return an NSPersistentStoreResult which may contain additional information about the result of the action
    // (ie a batch update result may contain the object IDs of the objects that were modified during the update).
    // A request may succeed in some stores and fail in others. In this case, the error will contain information
    // about each individual store failure.
    // Will always reject NSSaveChangesRequests.
    @available(iOS 8.0, *)
    open func execute(_ request: NSPersistentStoreRequest) throws -> NSPersistentStoreResult
    

    例如可能是下面的方法(scratchy)

    // somewhere in View declaration
    @State private var refreshingID = UUID()
    
    ...
    // somewhere in presenting fetch results
    ForEach(fetchedResults) { item in
        ...
    }.id(refreshingID) // < unique id of fetched results
    
    ...
    
    // somewhere in bulk delete 
    try context.save() // < better to save everything pending
    try context.execute(deleteRequest)
    context.reset() // < reset context
    self.refreshingID = UUID() // < force refresh
    

    【讨论】:

    • 谢谢!这种方法效果很好。我希望这对其他人也有帮助,因为我在 Stackoverflow 的某个地方找不到这个非常简单的解决方案。 :-)
    • 在单独的视图中添加记录后,我遇到了同样的更新问题。因为我只使用列表视图中的上下文来执行删除,所以我重置了上下文并刷新了 .onAppear 中的 ID。我还不完全明白为什么它是必要的,甚至为什么它会起作用,但确实如此,所以谢谢!
    • 这不是最好的解决方案,因为 .id 会重新生成整个列表,而不是仅仅更新更改
    【解决方案2】:

    无需强制刷新,这是 IMO 不干净的解决方案。

    正如您在问题中正确提到的那样,内存中仍然存在元素。解决方案是在执行后使用mergeChanges 更新内存中的对象。

    blog postblog post 在“更新内存对象”下详细解释了解决方案。

    在那里,作者提供了NSBatchDeleteRequest的扩展如下

    extension NSManagedObjectContext {
        
        /// Executes the given `NSBatchDeleteRequest` and directly merges the changes to bring the given managed object context up to date.
        ///
        /// - Parameter batchDeleteRequest: The `NSBatchDeleteRequest` to execute.
        /// - Throws: An error if anything went wrong executing the batch deletion.
        public func executeAndMergeChanges(using batchDeleteRequest: NSBatchDeleteRequest) throws {
            batchDeleteRequest.resultType = .resultTypeObjectIDs
            let result = try execute(batchDeleteRequest) as? NSBatchDeleteResult
            let changes: [AnyHashable: Any] = [NSDeletedObjectsKey: result?.result as? [NSManagedObjectID] ?? []]
            NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self])
        }
    }
    

    以下是关于如何调用它的代码更新:

    func deleteAll() {
        let fetchRequest: NSFetchRequest<NSFetchRequestResult> = ToDoItem.fetchRequest()
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
    
        let persistentContainer = (UIApplication.shared.delegate as! AppDelegate).persistentContainer
    
        do {
            try persistentContainer.viewContext.executeAndMergeChanges(deleteRequest)
        } catch let error as NSError {
            print(error)
        }
    }
    

    此链接下还有更多信息:Core Data NSBatchDeleteRequest appears to leave objects in context

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-12
      • 1970-01-01
      • 2020-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多