本文介绍了viewContext.execute(deleteRequest) 不会调用重绘 SwiftUI 列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不明白当我尝试通过调用 viewContext.execute(deleteRequest) 删除所有项目时,SwiftUI 不会重绘 UI.我看到来自 sqlite 的项目不见了.

I don't understand when I try to remove all items by calling viewContext.execute(deleteRequest) SwiftUI doesn't redraw UI.I see items from sqlite are gone.

struct CloudKitTestView: View {
    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
        animation: .default)
    private var items: FetchedResults<Item>

    var body: some View {
        VStack {
            Button("Remove all") {
                let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Item")
                let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

                do {
                    try viewContext.execute(deleteRequest)
                } catch {
                    // Replace this implementation with code to handle the error appropriately.
                    // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                    let nsError = error as NSError
                    fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
                }
            }

            List {
                ForEach(items) { item in
                    Text("Item at \(item.timestamp!, formatter: itemFormatter)")
                }
                .onDelete(perform: deleteItems)
            }
            .toolbar {
                #if os(iOS)
                EditButton()
                #endif

                Button(action: addItem) {
                    Label("Add Item", systemImage: "plus")
                }
            }
        }
    }

    private func addItem() {
        withAnimation {
            let newItem = Item(context: viewContext)
            newItem.timestamp = Date()

            do {
                try viewContext.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            offsets.map { items[$0] }.forEach(viewContext.delete)

            do {
                try viewContext.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }
}

推荐答案

Core Data 批量更新不会更新内存中的对象.之后您必须手动刷新.

Core Data batch updates do not update the in-memory objects. You have to manually refresh afterwards.

批量操作绕过普通的 Core Data 操作,直接在底层 SQLite 数据库(或任何支持持久存储的数据库)上操作.他们这样做是为了提高速度,但这意味着他们也不会触发您使用正常获取请求获得的所有内容.

Batch operations bypass the normal Core Data operations and operate directly on the underlying SQLite database (or whatever is backing your persistent store). They do this for benefits of speed but it means they also don't trigger all the stuff you get using normal fetch requests.

您需要执行 Apple 的 Core Data Batch Programming Guide:Implementing Batch Updates - Updating Your Application After Execution 中所示的操作

You need to do something like shown in Apple's Core Data Batch Programming Guide: Implementing Batch Updates - Updating Your Application After Execution

原答案

do {
    let fetch: NSFetchRequest<NSFetchRequestResult> = Item.fetchRequest()
    let request = NSBatchDeleteRequest(fetchRequest: fetch)

    request.resultType = .resultTypeObjectIDs

    let result = try viewContext.execute(request) as? NSBatchDeleteResult
    let objIDArray = result?.result as? [NSManagedObjectID]
    let changes = [NSDeletedObjectsKey: objIDArray]

    NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [viewContext])
} catch {
    let nsError = error as NSError
    fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}

这篇关于viewContext.execute(deleteRequest) 不会调用重绘 SwiftUI 列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 11:40