【问题标题】:SwiftUI View Property willSet & didSet property observers not workingSwiftUI 查看属性 willSet 和 didSet 属性观察者不起作用
【发布时间】:2019-12-20 10:33:50
【问题描述】:

我有一个带有附加 ViewModel 的 SwiftUI(Beta 5)视图。我想通过 navigationLink 导航到它并传入一个简单的参数(在本例中称为 FSAC)

我使用导航

NavigationLink("Next", destination: MyTestView(FSAC: "testFsac"))

视图有一个带有 willSet 和 didSet 属性观察者的 FSAC 属性

struct MyTestView: View {
    @ObservedObject var vm = MyTestViewModel()

var FSAC: String {
    willSet {
        print("will set fsac")
    }
    didSet {
        print("did set fsac")
        vm.FSAC = FSAC
    }
}

var body: some View {
    VStack {
        Text("FSAC: \(FSAC)")
        Text("VM FSAC: \(vm.FSAC)")
    }
}

}

永远不会调用打印语句。第一个文本框正确显示参数;第二个是空白的。

如何让 Property Observers 触发?

更一般地说,是否有一种“正确”的方式来使用 navigationLink 将参数传递给具有 ViewModel 的 View?

【问题讨论】:

  • 对我来说可能是一个愚蠢的问题,但你为什么要在View 中设置这样的属性?你已经有了MyTestViewModel——不应该在那里做这样的事情,让MyTestView对模型的状态变化做出反应吗?
  • @dfd 我正在传递参数,因为正如我所见,NavigationLink 要求我将其传递(参见我的第一个代码 sn-p: MyTestView(FSAC: "testFsac") )。我可以在 NavigationLink 中实例化并传入整个 ViewModel 类,但这感觉就像超出了调用视图的单一职责。
  • 就像我说的,这可能是一个愚蠢的问题。我不使用NavigationLink - 不需要。但是,考虑到这是一个 SwiftUI 视图,我认为您可以创建两个“测试”变量......将它们设为 @State...... 看看有什么用。当我完成此操作时,@State 是关键部分。如果是这样 - 如果我不知道NavigationLink,那么这不是意味着你可以使用你的ObservableObject 吗? “更一般地说,是否有一种“正确”的方式来使用 navigationLink 将参数传递给具有 ViewModel 的视图?” 是否已经回答了这个问题,但您搜索的是错误的术语?我经常这样做——称之为斗牛!
  • 试试这个,它有效! stackoverflow.com/a/59391476/8457280

标签: swift mvvm viewmodel swiftui didset


【解决方案1】:

编辑: 在 iOS 14 上,属性观察器的工作方式与在 iOS 13 中相同。但是,我们现在有 .onChange(of:perform:) 作为替代品。 Docs

Text(self.myString).onChange(of: self.myString) { newValue in print("myString changed to: \(newValue)") }

vars 上的属性观察者技术上在 SwiftUI 中工作。如果您执行var view = MyTestView(...)view.FSAC = "updated" 之类的操作,则观察者将触发(我已经验证了这一点)。

但是,通常使用 SwiftUI,您在每个布局过程中构建 body 内的View(它是一个结构 不是一个类)。在你的情况下var body: some View { MyTestView(FSAC: "FSAC Value") }

属性观察器在初始化期间不会触发,因此它们在 SwiftUI Views 中通常没有用处。

如果您想在初始化期间更新某种状态,请查看this answer

【讨论】:

    【解决方案2】:

    感谢 arsenius 解释了为什么在这种情况下 Property Observers 没有触发。

    作为修复,我删除了视图中的属性,并将其替换为带有签名的 init 函数,其中包含要从 NavigationLink 调用传递的所需数据。在 init 中,我直接在 ViewModel 上调用了一个函数。

    struct MyTestView: View {
    
        @ObservedObject var vm = MyTestViewModel()
    
        init(FSAC: String) {
            if(FSAC != "") {
                vm.SetFsac(FSAC: FSAC)
            }
        }
    ...
    

    【讨论】:

      【解决方案3】:

      也设法解决了我的问题,我在视图中有一个切换开关,但没有被触发。将用于切换的绑定变量移动到观察对象,即我的(视图)模型和从那里公开的已发布属性。使用 Andy 和 arsenius 的信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-05
        • 1970-01-01
        • 2016-04-22
        • 1970-01-01
        相关资源
        最近更新 更多