SwiftUI - 将详细视图更改为 @fetchRequest 弹出导航链接视图

Dja*_*aum 8 ios swift swiftui

我有两种看法。一个视图是使用 @fetchRequest 从核心数据存储中获取的对象(人员)列表。另一个视图是详细视图,用户可以通过点击列表视图中的个人项目来导航到该视图。这个想法是用户可以在详细信息视图中编辑人员的详细信息(例如姓名、年龄)。到目前为止,一切都很好。

关键点是列表视图的设计使得并非所有人员都必须从核心数据存储中获取。仅提取满足特定标准的人员。我们假设标准是该人的年龄必须在 30 岁到 40 岁之间。

我的问题是,当用户将详细视图中某人的年龄更改为不满足获取请求标准的某个年龄时(例如,他将年龄从 35 岁更改为 20 岁),一旦用户点击保存按钮,托管对象上下文就会保存,该上下文由@fetchRequest 在列表视图中注册。

我知道会发生这种情况,因为驱动列表视图的人的 fetchRequest 会发生变化,因为编辑的人被删除,因为他不再满足 30 到 40 岁之间的要求。但我不希望在用户仍处于详细视图中时发生这种情况。点击保存按钮不应自​​动弹出详细视图。使用@fetchRequest时有什么办法可以防止这种情况发生吗?

以下是导致所描述问题的代码的精简版本:

struct PersonList: View {
    @FetchRequest var persons: FetchedResults<Person>
    
    init() {
        let lowerAge = NSPredicate(format: "%K >= %@", #keyPath(Person.age), 30 as CVarArg)
        let upperAge = NSPredicate(format: "%K <= %@", #keyPath(Person.age), 40 as CVarArg)
        let agePredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [lowerAge, upperAge])
        _persons = FetchRequest(entity: Person.entity(), sortDescriptors: [], predicate: agePredicate)
    }
    
    var body: some View {
      NavigationView {
        ScrollView(showsIndicators: false) {
            LazyVStack(spacing: 10) {
                ForEach(persons, id: \.id) { person in
                    NavigationLink(destination: PersonDetail(person: person)) {
                        Text(person.name)
                    }
                }
            }
        }
      }
}

struct PersonDetail: View {
    @Environment(\.managedObjectContext) var viewContext
    @State var ageInput: String = ""
    var person: Person
    
    var body: some View {
        TextField("Enter Age", text: $ageInput)
        .onAppear(perform: {
           ageInput = "\(person.age)"
        })
        Button("Save", action: { save() } )
        }
    }

    func save() {
        if let age = Int(ageInput) {
            viewContext.saveContext()
        }     
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 6

正如您所指出的,NavigationLink由于底层模型已从获取请求中删除,所以会弹出。不幸的是,这意味着您必须将导航链接移到列表视图之外,以便即使模型从获取结果列表中删除,您也可以缓存模型。

一种方法是将 VStack/ScrollView 嵌入 ZStack 中,并使用隐藏的“单例”导航链接和 @State 变量来跟踪主动选择的 Person:

struct PersonList: View {
    @FetchRequest var persons: FetchedResults<Person>

    @State private var selectedPerson = Person(entity: Person.entity(), insertInto: nil)
    @State private var showPersonDetail = false

    var body: some View {
        NavigationView {
            ZStack {
                NavigationLink(destination: PersonDetail(person: selectedPerson), isActive: $showPersonDetail) { EmptyView() }.hidden()
                ScrollView(showsIndicators: false) {
                    LazyVStack(spacing: 10) {
                        ForEach(persons, id: \.id) { person in
                            Button(action: {
                                selectedPerson = person
                                showPersonDetail = true
                            }, label: {
                                // You could hack out the click/tap listener for a navigation link instead of
                                // emulating its appearance, but that hack could stop working in a future iOS release.
                                HStack {
                                    Text(person.name)
                                    Spacer()
                                    Image(systemName: "chevron.right")
                                }
                            })
                        }
                    }
                }
          }
      }
}
Run Code Online (Sandbox Code Playgroud)