使用Core Data在SwiftUI中导航到详细视图

3
我正在尝试构建一个例子BBQ应用程序来学习SwiftUI(XCode 11 beta 5),但一直无法弄清如何从Core Data中一个对象的列表视图导航到该对象的详细信息视图。 Xcode并没有提供帮助,根据我尝试的内容,它主要会弹出无关的错误。
我已经尽力应用状态、绑定、可观察对象等方法解决问题,但还是不能解决它。
这是我的列表视图,可以很好地构建,并允许我导航到目标(这只是一个包含id属性作为字符串的视图):
struct CookListView: View {

    @ObservedObject var cookListVM: CookListViewModel
    @State var cookCreatorVM = CookCreatorViewModel()

    init() {
        cookListVM = CookListViewModel()
    }

    var body: some View {


        NavigationView {
            List {
                ForEach(cookListVM.cooks, id: \.id) { cook in
                    NavigationLink(destination: Text("\(cook.id)")) {
                        VStack {
                            Text(cook.protein)
                        }
                    }
                }
            }.navigationBarTitle("BBQ")
        }
    }
}

但如果我将我的 NavigationLink 目标修改如下:

NavigationView {
    List {
        ForEach(cookListVM.cooks, id: \.id) { cook in
            NavigationLink(destination: CookDetailView(cook: cook)) {
                VStack {
                    Text(cook.protein)
                }
            }
        }
    }
}

Xcode将不再构建该项目。它给我的错误似乎与此无关,例如在ForEach行上出现“Type'_'has no member'id'”,或者如果我从ForEach中删除“, id:\.id”(由于Identifiable我不是真正需要它),我将在Text(cook.protein)行上得到“Type of expression is ambiguous without more context”的错误。
如果我使用硬编码数组,它会构建并可以完美地导航。只有在我尝试使用Core Data时才会出现问题。
我的CookDetailView如下所示:
struct CookDetailView: View {
    var cook: Cook
    var body: some View {
        VStack {
            Text("\(cook.protein!)")
        }
    }
}

Cook 对象本身的模型如下所示:

class CookViewModel: ObservableObject, Identifiable {

    var protein: String = ""
    var type: String = ""
    var id: UUID = UUID()

    init(cook: Cook){
        self.protein = cook.protein!
        self.type = cook.type!
        self.id = UUID()
    }
}

这也可以通过.xcdatamodeld文件进行设置。

如果有帮助的话,我很乐意添加任何额外/遗漏的代码,例如如何写入/读取核心数据。


1
我认为这不是与CoreData相关的问题,但为了我们能够复制并尝试找出问题,我们需要所有代码作为最小可行示例。例如:Cook类丢失,我无法复制您的代码并尝试调试。 - superpuccio
cook.protein 是可选的吗?您可以将 { cook in 替换为 { (cook: CookType) in。从标签周围删除 VStack。如果两个参数中有一个是 Label,则更有可能起作用。如果尝试传递绑定,可能会变得更加复杂。特别是如果它由计算数组支持...但我们不要深入讨论。哦,您可以将 cook.protein 添加为第一个未命名参数,这更有可能起作用,同时删除尾随闭包。耶。SwiftUI! - Fabian
由于我们无法看到您的代码的其余部分,请查看此项目。该项目已完整编译并在Beta 5上运行。它可能会给您一些关于您的项目方向的想法。 https://github.com/Whiffer/SwiftUI-Core-Data-Test - Chuck H
1个回答

2
我完全理解你对Xcode错误消息的沮丧。实际错误往往与错误消息无关。【建议:使用源代码控制,在每次干净编译后提交;-)】在您的列表视图中出现的错误是因为您在详细视图的参数列表中指定了错误的类型。请尝试以下操作:
struct CookDetailView: View {

    var cook: CookViewModel

    var body: some View {
        VStack {
            Text("\(cook.name)")
        }
    }
}

顺便提一下,由于你正在将内容获取到一个数组中,因此除非你手动发布更改,否则你将不会观察到该数组中的更改。我放弃了尝试让我的NSManagedObject子类发布它们自己的更改。有两种解决方法。您可以从NSFetchedResultsControllercontrollerDidChangeContent代理中调用objectWillChange,或者在不使用获取结果控制器时观察NSManagedObjectContextDidSave通知并执行相同操作。

此答案适用于Beta 5。未来的beta版本肯定会有所改变。


解决了!你不会相信我为这个问题苦思冥想了多久。非常感谢你的解决方案、示例项目和技巧——它们都非常有帮助。 - immediateorchestra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接