首页 > 解决方案 > SwiftUI 在 Bindable 属性更改时运行方法调用

问题描述

我正在努力理解如何在 Bindable 对象更改时运行方法。这是我到目前为止的代码: 在此处输入图像描述

但是,由于某种原因,由于 searchText 的变化,fetchFoods 方法永远不会被调用,我似乎无法理解为什么。

标签: iosswiftswiftui

解决方案


@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()
    }
}

如果您复制粘贴并运行这个最小可行示例,您将看到字符串“已触发!” 永远不会被打印出来。这是因为您通过 $ 绑定更改的不是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 对象更改时运行方法”)?您必须依赖 aViewModel@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


推荐阅读