xcode SwiftUI:NavigationLink导致冻结@99%调试CPU

rqcrx0a6  于 2023-05-01  发布在  Swift
关注(0)|答案(1)|浏览(110)

我是Swift和SwiftUI的新手,正在开发一个需要通过各种视图传递嵌套绑定的应用程序。我遇到了一个问题,子视图中的NavigationLink将绑定传递给子详细视图,导致应用程序在真实的设备和模拟器上测试时完全冻结。但是,它不会在SwiftUI预览画布中冻结。
我创建了一个精简的项目来测试这个问题仍然存在。我还尝试通过工作表显示子详细视图,但绑定在工作表视图中不更新。
有谁能看出是否有什么明显的错误导致了这个问题?
ParentDetail视图中的NavigationLink导致冻结。下面是示例代码:
基本型号:

import SwiftUI

class ParentStore: ObservableObject {
    @Published var parents = [ParentObject.parentExample]
    
    func binding(for parentID: UUID) -> Binding<ParentObject> {
        Binding {
            guard let index = self.parents.firstIndex(where: { $0.id == parentID }) else {
                fatalError()
            }
            
            return self.parents[index]
        } set: { updatedParent in
            guard let index = self.parents.firstIndex(where: { $0.id == parentID}) else {
                fatalError()
            }
            return self.parents[index] = updatedParent
        }
    }

}

struct ParentObject: Identifiable {
    var id = UUID()
    var name: String
    var children: [Child]
    
    static let parentExample = ParentObject(name: "Matt", children: [.sasha, .brody])
    static let emptyParent = ParentObject(name: "Empty", children: [])
}

struct Child: Identifiable {
    var id = UUID()
    var name: String
    var grandkids: [Grandkid]
    
    static let sasha = Child(name: "Sasha", grandkids: [.peter, .meagan])
    static let brody = Child(name: "Brody", grandkids: [.michelle])
}

struct Grandkid: Identifiable {
    var id = UUID()
    var name: String
    
    static let peter = Grandkid(name: "Peter")
    static let meagan = Grandkid(name: "Meagan")
    static let michelle = Grandkid(name: "Michelle")
}

主视图:

struct ContentView: View {
    @StateObject var parentStore = ParentStore()
    
    var body: some View {
        TabView {
            ParentList()
                .environmentObject(parentStore)
                .tabItem {
                    Label("List", systemImage: "list.bullet")
                }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

家长名单:

struct ParentList: View {
    @EnvironmentObject var parentStore: ParentStore
    
    var body: some View {
        NavigationStack {
            List {
                ForEach($parentStore.parents) { $parent in
                    NavigationLink(parent.name, value: parent.id)
                }
            }
            .navigationDestination(for: UUID.self) { parentID in
                ParentDetail(parent: parentStore.binding(for: parentID))
            }
        }
    }
}

struct ParentList_Previews: PreviewProvider {
    static var previews: some View {
        ParentList()
            .environmentObject(ParentStore())
    }
}

ParentDetailView:

struct ParentDetail: View {
    @Binding var parent: ParentObject
    @State private var child: Binding<Child>?
    
    var body: some View {
        List {
            Section("Parent") {
                Text(parent.name)
            }
            
            Section("Children") {
                ForEach($parent.children) { $child in
// This navigation link causes the freeze
                    NavigationLink(child.name) {
                        ChildDetail(child: $child)
                    }
                    // Testing sheet presentation...
                    Button(child.name) {
                        self.child = $child
                    }

                }
            }
        }
        .sheet(item: $child) { $child in
            ChildDetail(child: $child)
        }
    }
}

struct ParentDetail_Previews: PreviewProvider {
    static var previews: some View {
        ParentDetail(parent: .constant(.parentExample))
    }
}

子详细视图:

struct ChildDetail: View {
    @Binding var child: Child
    
    var body: some View {
        VStack {
            TextField("Name", text: $child.name)
            
            ForEach(child.grandkids) { grandkid in
                Text(grandkid.name)
            }
        }
    }
}

struct ChildDetail_Previews: PreviewProvider {
    static var previews: some View {
        ChildDetail(child: .constant(.sasha))
    }
}
relj7zay

relj7zay1#

你需要替换这个:

NavigationLink(child.name) {
    ChildDetail(child: $child)
}

使用相同的值/目的地新的API,因为你在父母中使用,因为我不认为你可以使用它沿着旧的视图为基础的版本,e。g的。

NavigationLink(child.name, value: child.id)

.navigationDestination(for: Child.ID.self) { childID in
    ChildDetail(parent: store.binding(for: childID))
}

最好也编辑一下:

.navigationDestination(for: Parent.ID.self) { parentID in

我还建议重新构建数据模型,使用Person结构体,而不是Parent和Child,它们本质上是一样的。然后,您可以将子ID到ID关系存储在数组中。当使用数据而不是对象的值类型时,我们必须以不同的方式组织事物。

相关问题