SwiftUI 4:当状态更改时,navigationDestination() 的目标视图不会更新

ray*_*ayx 5 ios swiftui swiftui-navigationsplitview

在尝试 SwiftUI 4 中的新功能时NavigationStack,我发现当状态更改时,返回的目标视图navigationDestination()不会更新。请参阅下面的代码。

struct ContentView: View {
    @State var data: [Int: String] = [
        1: "One",
        2: "Two",
        3: "Three",
        4: "Four"
    ]

    var body: some View {
        NavigationStack {
            List {
                ForEach(Array(data.keys).sorted(), id: \.self) { key in
                    NavigationLink("\(key)", value: key)
                }
            }
            .navigationDestination(for: Int.self) { key in
                if let value = data[key] {
                    VStack {
                        Text("This is \(value)").padding()
                        Button("Modify It") {
                            data[key] = "X"
                        }
                    }
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

重现问题的步骤:

  1. 运行代码并单击列表中的第一项。这将带您进入该项目的详细视图。

  2. 详细视图显示了该项目的价值。它还具有一个用于修改值的按钮。单击该按钮。您会发现详细视图中的值没有改变。

我通过在不同位置设置断点来调试该问题。我的观察:

  • 当我点击按钮时,代码就会List被执行。这正如预期的那样。

  • 但是传递给的闭包navigationDestination() 没有被执行,这解释了为什么详细视图没有更新。

有谁知道这是错误还是预期行为?如果这不是错误,我该如何编程才能更新详细视图中的值?

顺便说一句,如果我返回根视图并单击第一个项目再次转到其详细信息视图,则传递的闭包将被navigationDestination()执行,并且详细信息视图会正确显示修改后的值。

Tim*_*mmy 1

正在正确更改该button值。默认情况下,不会在传递值的父级和子级之间navigationDestination创建关系。Bindingimmutable

所以你应该struct为孩子创建一个单独的以实现Bindable行为:

struct ContentView: View {
    @State var data: [Int: String] = [
        1: "One",
        2: "Two",
        3: "Three",
        4: "Four"
    ]

    var body: some View {
        NavigationStack {
            List {
                ForEach(Array(data.keys).sorted(), id: \.self) { key in
                    NavigationLink("\(key)", value: key)
                }
            }
            .navigationDestination(for: Int.self) { key in
                SubContentView(key: key, data: $data)
            }
        }
    }
}

struct SubContentView: View {
    let key: Int
    @Binding var data: [Int: String]
    var body: some View {
        if let value = data[key] {
            VStack {
                Text("This is \(value)").padding()
                Button("Modify It") {
                    data[key] = "X"
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)