SwiftUI:手动发布 ObservableObject 更改

符合ObservableObject协议的类可以使用SwiftUI的@Published属性包装器自动声明对属性的更改,以便使用该对象的所有视图都可以重新调用其body属性,并与数据保持同步。在很多时候,这确实非常有效,但是有时您需要更多的控制权,而SwiftUI的解决方案称为objectWillChange

每个符合ObservableObject的类都会自动获得一个名为objectWillChange的属性。这是一个发布者,这意味着它执行与@Published属性包装器相同的工作:它通知正在观察该对象的所有视图一些重要的更改。顾名思义,此发布者应在我们进行更改之前立即触发,这使SwiftUI可以检查UI的状态并为动画更改做准备。

为了演示这一点,我们将构建一个可更新10次的ObservableObject类。您已经认识到DispatchQueue.main.async()是将工作推送到主线程的一种方式,但是在这里,我们将使用一种称为DispatchQueue.main.asyncAfter()的类似方法。这使我们可以指定何时运行附加的闭包,这意味着我们可以说“在1秒钟后执行此工作”,而不是“立即执行此工作”。

在此测试用例中,我们将在1到10的循环内使用asyncAfter(),因此我们将整数增加10个值。该整数将使用@Published进行包装,因此更改公告将发送到所有正在观看它的视图。

在您的代码中的某处添加此类:

class DelayedUpdater: ObservableObject {
    @Published var value = 0

    init() {
        for i in 1...10 {
            DispatchQueue.main.asyncAfter(deadline: .now() + Double(i)) {
                self.value += 1
            }
        }
    }
}

要使用它,我们只需要在ContentView中添加一个@ObservedObject属性,然后在我们的主体中显示该值,如下所示:

struct ContentView: View {
    @ObservedObject var updater = DelayedUpdater()

    var body: some View {
        Text("Value is: \(updater.value)")
    }
}

运行该代码时,您会看到该值一直递增,直到达到10,这正是您所期望的。

现在,如果删除@Published属性包装,您将看到UI不再更改。在后台,所有的asyncAfter()工作仍在进行,但不会导致UI刷新,因为没有发出更改通知。

尝试将value属性更改成如下内容:

var value = 0 {
    willSet {
        objectWillChange.send()
    }
}
SwiftUI:手动发布 ObservableObject 更改_第1张图片

现在,您将再次恢复原来的行为——用户界面将像以前一样计数为10。除了这次,我们有机会在willSet观察器中添加额外的功能。也许您想要记录一些东西,也许您想要调用另一个方法,或者您想要钳制整数内部值,以使它永远不会超出范围——现在所有这些都在我们的控制之下。

译自 Manually publishing ObservableObject changes

你可能感兴趣的:(SwiftUI:手动发布 ObservableObject 更改)