@State和@Binding如何并行使用?

How to use @State and @Binding parallel?

我的设置: 我有一个 ContentView 代表最终 selection (selection.count) 的长度。因此,我需要在 ContentView 上使用 @State propertyWrapperselection 变量,因为我希望 View 在值更改时立即更新。该选择应该在我的 SelectionView 上进行,因此我在 ContentViewSelectionView 上的 selection 变量之间创建了一个 Binding

我的问题: 我的 SelectionView 上的 UI 也应该在 selection 变量更改时更新,但由于它使用 @Binding 而不是 @State 视图不会更新。所以我需要一些可以同时使用 @State@Binding@Binding 的东西,它也可以使 UI 重新加载。

struct ContentView: View {
    @State var selection: [Int] = []

    var body: some View {
        NavigationView {
            Form {
                NavigationLink(destination: SelectionView(selection: $selection)) {
                    Text("Selection: \(selection.count)")
                }
            }
        }
    }
}

struct SelectionView: View {
    @Binding var selection: [Int]

    var body: some View {
        NavigationView {
            Form {
                ForEach((0...9).identified(by: \.self)) { i in
                    Button(action: {
                        if self.selection.contains(i) {
                            self.selection = self.selection.filter { !([=10=] == i) }
                        } else {
                            self.selection.append(i)
                        }
                    }) {
                        if self.selection.contains(i) {
                            Text("Unselect \(i)")
                        } else {
                            Text("Select \(i)")
                        }
                    }
                }
            }
        }
    }
}

注意: 如果我在 SelectionView 上使用 @State 而不是 @Binding 它可以正常工作(这显然需要我不创建我想要的绑定)。

你的绑定没有问题。这是正确的做法,并且会按照您希望的方式工作。绑定是您在 SwiftUI 中传递可变状态的方式,您正在这样做,并且它有效。对绑定的更改 确实 使视图重新加载。

为了让自己相信这一点,只需去掉示例中的所有额外内容,并专注于问题的核心,即绑定:

struct ContentView: View {
    @State var selection: [Int] = []
    var body: some View {
        NavigationView {
            Form {
                NavigationLink(destination: SelectionView(selection: $selection)) {
                    Text("Selection: \(selection.count)")
                }
            }
        }
    }
}
struct SelectionView: View {
    @Binding var selection: [Int]
    var body: some View {
        NavigationView {
            VStack {
                Button.init("Append") {
                    self.selection.append(1)
                }
                Text("Selection: \(selection.count)")
            }
        }
    }
}

运行例子,点击link,重复点击按钮。 selection.count 的显示在两个视图中都发生了变化。这就是你想要的,这就是发生的事情。

这是原始代码的一个变体,它更明确地显示 selection(而不是 selection.count),您可以看到正确的事情正在发生:

struct ContentView: View {
    @State var selection: [Int] = []
    var body: some View {
        NavigationView {
            Form {
                NavigationLink(destination: SelectionView(selection: $selection)) {
                    Text("Selection: \(String(describing:selection))")
                }
            }
        }
    }
}
struct SelectionView: View {
    @Binding var selection: [Int]
    var body: some View {
        NavigationView {
            List {
                ForEach(0...9, id:\.self) { i in
                    Button(action: {
                        if let ix = self.selection.firstIndex(of:i) {
                            self.selection.remove(at: ix)
                        } else {
                            self.selection.append(i)
                        }
                    }) {
                        if self.selection.contains(i) {
                            Text("Unselect \(i)")
                        } else {
                            Text("Select \(i)")
                        }
                    }
                }
            }
        }
    }
}

您的问题的解决方法是:升级到最新的Xcode。


我在操场上用 Xcode 11 beta 4 测试了你的代码,它工作正常。

我在 Xcode 11 beta 3 下的操场上测试了你的代码,但它以你描述的方式失败了(我认为)。

截至此答案,Xcode 11 的当前版本是 beta 5,在该版本下您的代码无法编译,因为 identified(by:) 修饰符已被删除。当我将您的代码更改为在 beta 5 下工作时,通过将 ForEach((0...9).identified(by: \.self)) 替换为 ForEach(0...9, id: \.self),它工作正常。

因此我推断您仍然是 运行 beta 2 或 beta 3。(Form 在 beta 1 中不可用,所以我知道您没有使用该版本。)


请理解,目前,SwiftUI 仍然存在很多问题,并且仍在进行不兼容的 API 更改。错误是不幸的,但 API 进化是 。我们现在经历几个月的变化总比以后经历几年不太理想的变化要好API。

这意味着您需要尝试使用最新的 Xcode 11 测试版,除非它引入了错误(例如 beta 5 中的 Path 错误,如果您的应用使用 Path ) 阻碍你取得任何进展。

感谢@robmayoff 我能够解决问题。 Xcode 11 Beta 3 有问题,安装最新的测试版解决了问题