使用 SwiftUI、Core Data 和一对多关系,为什么在多方添加行时列表不更新

Ton*_*ler 6 core-data relationship swiftui

我有一个带有 Core Data 的 SwiftUI 项目。数据模型是一个简单的一对多和两个主要视图,每个视图的顶部都有一个文本字段和一个用于将新项目添加到下面的列表视图的按钮。第一种观点适用于关系的一方,第二种观点适用于多方。因此,第一个中的 NavigationLink 打开第二个并传递 One 对象。看起来相当标准的东西。创建 One 的方法有效,并且当托管对象上下文保存新项目时,下面的列表会立即更新。但是,在设备上查看时,相同类型的方法不会刷新多方的列表,尽管它在模拟器和预览窗口中运行良好。数据肯定会被保存,因为如果您导航回“一侧”然后重新选择它以重新加载“许多”视图,它会在列表中显示新项目。

我浏览了很多教程、其他问题等,但没有找到原因。我在访问关系的多方方面是否做错了什么,或者我还需要做些什么才能仅刷新多方的视图?谢谢!!!

完整项目可在https://github.com/fahrsoft/OneToManyTest获取

从 ContentView 中,显示一侧(注意:OneView 是一个简单的视图,它获取对象并显示文本。ManyView 也是如此。):

struct ContentView: View {
@Environment(\.managedObjectContext) var moc
@FetchRequest(entity: One.entity(), sortDescriptors: []) var ones: FetchedResults<One>

@State private var newName = ""
@State var isNavTitleHidden = true

var body: some View {
    NavigationView {
        VStack {
            HStack {
                TextField("New One", text: self.$newName)
                Spacer()
                Button(action: {
                    let newOne = One(context: self.moc)
                    newOne.name = self.newName
                    self.newName = ""
                    try? self.moc.save()
                }) {
                    Image(systemName: "plus.circle.fill")
                        .foregroundColor(.green)
                        .frame(width: 32, height: 32, alignment: .center)
                }
            }
            .padding(.top)
            .padding(.horizontal)

            List {
                Section(header: Text("Ones")) {
                    ForEach(self.ones, id:\.self) { (one:One) in
                        NavigationLink(destination: OneDetailView(one: one, isNavTitleHidden: self.$isNavTitleHidden).environment(\.managedObjectContext, self.moc)) {
                            OneView(one: one).environment(\.managedObjectContext, self.moc)
                        }
                    }

                    .onDelete { indexSet in
                        let deleteOne = self.ones[indexSet.first!]
                        self.moc.delete(deleteOne)
                        do {
                            try self.moc.save()
                        } catch {
                            print(error)
                        }
                    }
                }
            }
        }
        .navigationBarTitle(Text("Ones List"))
        .navigationBarHidden(self.isNavTitleHidden)
        .onAppear {
            self.isNavTitleHidden = true
        }
    }
}}
Run Code Online (Sandbox Code Playgroud)

从显示多方的 OneDetailView 来看:

struct OneDetailView: View {
@Environment(\.managedObjectContext) var moc

@ObservedObject var one: One

@State private var newManyAttribute = ""
@Binding var isNavTitleHidden: Bool

var body: some View {
    VStack {
        HStack {
            TextField("New Many", text: self.$newManyAttribute)
            Spacer()
            Button(action: {
                let newMany = Many(context: self.moc)
                newMany.attribute = self.newManyAttribute
                self.newManyAttribute = ""
                self.one.addToMany(newMany)
                try? self.moc.save()
            }) {
                Image(systemName: "plus.circle.fill")
                    .foregroundColor(.green)
                    .frame(width: 32, height: 32, alignment: .center)
            }
        }
        .padding(.top)
        .padding(.horizontal)

        List {
            Section(header: Text("Manys")) {
                ForEach(self.one.manyArray, id: \.self) { many in
                    ManyView(many: many).environment(\.managedObjectContext, self.moc)
                }
            }
        }
    }
    .navigationBarTitle("\(self.one.wrappedName) Details")
    .onAppear {
        self.isNavTitleHidden = false
    }
}}
Run Code Online (Sandbox Code Playgroud)

Ton*_*ler 1

我唯一能想到的让它正常工作的方法是使用谓词中选定的 One 为 Many 项目创建一个新的 FetchRequest。将 FetchRequest 和 init 添加到 OneDetailView 的开头允许更新列表。

struct OneDetailView: View {
@Environment(\.managedObjectContext) var moc

@ObservedObject var one: One

@State private var newManyAttribute = ""
@Binding var isNavTitleHidden: Bool

@FetchRequest var manys: FetchedResults<Many>

init(one: One, isNavTitleHidden: Binding<Bool>) {
    self.one = one
    self._isNavTitleHidden = isNavTitleHidden
    var predicate: NSPredicate?
    predicate = NSPredicate(format: "one = %@", one)
    self._manys = FetchRequest(
        entity: Many.entity(),
        sortDescriptors: [],
        predicate: predicate
    )
}

var body: some View {
    VStack {
        HStack {
            TextField("New Many", text: self.$newManyAttribute)
            Spacer()
            Button(action: {
                let newMany = Many(context: self.moc)
                newMany.attribute = self.newManyAttribute
                self.newManyAttribute = ""
                self.one.addToMany(newMany)
                try? self.moc.save()
            }) {
                Image(systemName: "plus.circle.fill")
                    .foregroundColor(.green)
                    .frame(width: 32, height: 32, alignment: .center)
            }
        }
        .padding(.top)
        .padding(.horizontal)

        List {
            Section(header: Text("Manys")) {
                ForEach(self.manys, id: \.self) { many in
                    ManyView(many: many).environment(\.managedObjectContext, self.moc)
                }
            }
        }
    }
    .navigationBarTitle("\(self.one.wrappedName) Details")
    .onAppear {
        self.isNavTitleHidden = false
    }
}}
Run Code Online (Sandbox Code Playgroud)