swiftui列表参考已删除的nsmanagedObjects

发布于 2025-02-06 09:20:01 字数 1807 浏览 0 评论 0原文

当使用@fetchrequest填充列表时,SwiftUI即使从商店中删除了删除的NSManageBoct,也将尝试访问已删除的NSManageBject(例如,通过Swipe Action)。

此错误非常常见且易于复制:只需使用默认的SwiftUI + Coredata模板创建一个新的Xcode项目即可。然后用此代码替换ContentView:

struct ContentView: View {
    @Environment(\.managedObjectContext) private var moc
    @FetchRequest(sortDescriptors: []) private var items: FetchedResults<Item>
    var body: some View {
        List {
            ForEach(items) { item in
                ItemRow(item: item)
            }
            .onDelete {
                $0.map{items[$0]}.forEach(moc.delete)
                try! moc.save()
            }
        }
        .toolbar {
            Button("Add") {
                let newItem = Item(context: moc)
                newItem.timestamp = Date()
                try! moc.save()
            }
        }
    }
}

struct ItemRow: View {
    @ObservedObject var item: Item
    var body: some View {
        Text("\(item.timestamp!)")
    }
}

将一些项目添加到列表中,然后滑动以删除一行:该应用将崩溃。 itemrow正在尝试使用现在删除的item绘制。

一种常见的解决方法故障检查中的子视图:

struct ItemRow: View {
    @ObservedObject var item: Item
    var body: some View {
        if !item.isFault {
            Text("\(item.timestamp!)")
        }
    }
}

但这是一个差的解决方案,并且具有副作用(对象未删除时可能是故障)。

此答案建议将删除包装在view> viewcontext.perform {}} 可以正常工作,但是崩溃仍然对我发生。

那里有更好的解决方案/解决方法吗?

When using @FetchRequest to populate a List, SwiftUI will attempt to access a deleted NSManagedObject even after it has been deleted from the store (for example, via swipe action).

This bug is very common and easy to reproduce: simply create a new Xcode project with the default SwiftUI + CoreData template. Then replace ContentView with this code:

struct ContentView: View {
    @Environment(\.managedObjectContext) private var moc
    @FetchRequest(sortDescriptors: []) private var items: FetchedResults<Item>
    var body: some View {
        List {
            ForEach(items) { item in
                ItemRow(item: item)
            }
            .onDelete {
                $0.map{items[$0]}.forEach(moc.delete)
                try! moc.save()
            }
        }
        .toolbar {
            Button("Add") {
                let newItem = Item(context: moc)
                newItem.timestamp = Date()
                try! moc.save()
            }
        }
    }
}

struct ItemRow: View {
    @ObservedObject var item: Item
    var body: some View {
        Text("\(item.timestamp!)")
    }
}

Add a few items to the list, then swipe to delete a row: the app will crash. An ItemRow is attempting to draw with the now-deleted Item.

A common workaround is to wrap the whole subview in a fault check:

struct ItemRow: View {
    @ObservedObject var item: Item
    var body: some View {
        if !item.isFault {
            Text("\(item.timestamp!)")
        }
    }
}

But this is a poor solution and has side effects (objects can be faults when not deleted).

This answer suggests that wrapping the deletion in viewContext.perform{} would work, but the crash still occurs for me.

Any better solutions/workarounds out there?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情绪失控 2025-02-13 09:20:02

这确实是obsevedObject切换到故障的结果,而timestamp!是武力解开的。该力拆开适用于完整对象,但不适合故障。

似乎有效的一种方法是在 foreach 级别上删除。 :

ForEach(items) { item in
  ItemRow(item: item)
    .swipeActions {
      Button("Delete", role: .destructive) {
        viewContext.delete(item)
        try? viewContext.save()
      }
    }
}

在任何方面,它都表明,即使使用 的简单nsmanagdobject,依赖属性的武力也带有风险。

This does seem to be the result of the ObservedObject switching to a fault as part of the delete operation, while timestamp! is force unwrapped. The force unwrap works for the full object but not the fault.

An approach which does seem to work is to remove the .onDelete action at the ForEach level, and replace it with a swipeAction at the row level:

ForEach(items) { item in
  ItemRow(item: item)
    .swipeActions {
      Button("Delete", role: .destructive) {
        viewContext.delete(item)
        try? viewContext.save()
      }
    }
}

In any respect, it shows that even with a simple NSManagedObject like Item, relying on force unwrapping of attributes comes with risks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文