答案 0 :(得分:0)
@Harish @Asperi,您在这里让人感到困惑。导致@Harish方法不被调用的特定原因。让我们创建一个简单的示例:
struct ContentView: View {
@State private var text = "" {
didSet {
print("Triggered!")
}
}
var body: some View {
VStack {
TextField("Type something...", text: $text)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
如果您复制粘贴并运行此最小可行示例,则会看到字符串“ Triggered!”。永远不会被打印。这是因为您通过$绑定进行更改的不是text
属性,而是通过$
符号访问的绑定包装值 。它们是完全不同的两件事。了解这一点非常重要。
那么,为什么@Asperi的示例起作用? (我稍微简化了它,以创建另一个最小可行的示例):
struct ContentView: View {
@State private var isOn = false {
didSet {
print("Triggered!")
}
}
var body: some View {
Button(
action: { self.isOn.toggle() },
label: { Text(self.isOn ? "Hide" : "Show") }
)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
这次,如果您复制粘贴此代码,则会看到“已触发!”将被打印。这很好,因为轻按按钮即可更改self.isOn
。这次您没有使用任何$
符号来访问绑定包装的值。
上面的示例似乎使用相同的方法,但实际上它们确实不同。同样,了解这种差异非常重要。那么,如何获得所需的内容(即“在Bindable对象更改时运行方法”)?您必须依靠ViewModel
和@Published
属性包装器:
class ViewModel: ObservableObject {
@Published var text = "" {
didSet {
print("Triggered!")
}
}
}
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
VStack {
TextField("Type something...", text: $viewModel.text)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
正是出于此目的:
Combine的Published属性包装器在精神上类似于其他属性包装器,允许 客户订阅@Published属性(通过$投影) 当值更改时接收更新。
来自https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md