合并如何知道ObservableObject实际上发生了变化

时间:2019-12-29 12:45:58

标签: swift combine

由Combine框架定义的ObservableObject协议具有一个objectWillChange发布者属性,该属性可让您知道此对象的属性何时会更改,这意味着,如果该发布者将在获取此将要更改的事件时读取其值,但仍会在更改前 读取其值,我想了解的是:

  • SwiftUI之类的框架如何知道似乎唯一可以订阅的事件是发生变化时,值实际上会发生更改变化(即:它们如何获得新值) 一个?底层机制是否是Combine框架中的公共可用API?
  • 如何在收到意志变更事件后如何获取ObservableObject的实际新值?

谢谢

3 个答案:

答案 0 :(得分:6)

SwiftUI不知道ObservableObject实际上 是否已更改。 SwiftUI信任您。如果您告诉它对象将更改(通过使objectWillChange发出输出),则SwiftUI将假定对象已更改,并计划显示更新。

我不确定100%为什么苹果选择objectWillChange作为信号。在WWDC 2019上,该属性实际上是didChange,而不是objectWillChange。他们在Xcode 11仍处于测试版时对其进行了更改。也许他们所做的是在objectWillChange发出时获取对象的状态,然后稍后在更新屏幕时再次获取对象,然后以某种方式比较这些值。

关于objectWillChange发出后如何获取对象的值,这取决于您。 SwiftUI通过注册CFRunLoopObserver活动的.beforeWaiting来实现这一目的。观察者运行时,它将重新呈现ObservableObject发出信号的所有视图。

请注意,如果您使用@Published属性将值存储在ObservableObject中,则可以使用$前缀来订阅属性的发布者。例如:

class MyObject: ObservableObject {
    @Published var value: Int = 0
}

let object = MyObject()
let ticket = object.$value
    .sink { print("new value: \($0); old value: \(object.value)") }

object.value = 1

Published包装器在您订阅时发布当前值,然后在每次更改时发布新值。但是请注意,它会在存储新值之前 进行发布,如上面的示例代码所示,输出如下:

new value: 0; old value: 0
new value: 1; old value: 0

答案 1 :(得分:1)

我所做的是添加到我需要更改

之后知道的每个ObservableObject
public var objectDidChange = ObservableObjectPublisher()

您可以订阅并在一切更改后手动调用 .send()

答案 2 :(得分:0)

SwiftUI通过ObservableObject包装器监听@ObservedObject事件

/// A dynamic view property that subscribes to a `ObservableObject` automatically invalidating the view
/// when it changes.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@propertyWrapper public struct ObservedObject<ObjectType> : DynamicProperty where ObjectType : ObservableObject {

看起来像DynamicProperty,这就是他们所说的

/// Represents a stored variable in a `View` type that is dynamically
/// updated from some external property of the view. These variables
/// will be given valid values immediately before `body()` is called.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol DynamicProperty {

    /// Called immediately before the view's body() function is
    /// executed, after updating the values of any dynamic properties
    /// stored in `self`.
    mutating func update()
}

因此,ObservedObject包装器会监听来自ObservableObject的已发布事件,并且一旦调用update()就会提供最新值(如果需要,很可能直接为其重新缓存以代替更新)致电)。