信号观察者能否访问 ReactiveCocoa 信号的最后发射值?

Can a signal observer get access to the last emitted value of a ReactiveCocoa signal?

我开始使用 ReactiveCocoa,但我仍在为一些基本概念而苦苦挣扎:

  1. 我的应用程序开始侦听地理位置数据(init 在我的视图模型中)
  2. 我的应用程序发出带有我当前位置的信号(didFindCurrentPosition 被调用)
  3. 我的视图控制器显示地图加载(viewDidLoad 在我的视图控制器中)
  4. 我的视图控制器开始观察当前位置信号(仍然viewDidLoad

我的问题是:完成第 2 步后,如果信号上没有发送其他事件,我的视图控制器就不会收到通知。

我的视图控制器如何访问信号的最后一个值? (即如何在第 3 步访问第 2 步发出的值?)

感谢您的帮助。

PS:ReactiveCocoa 看起来像一个很棒的库,但我对文档的状态感到困惑。恕我直言,它不是很清楚并且缺乏一些关于如何使用它的明确指南。

代码

视图模型:

class MyViewModel: LocationManagerDelegate {
    let locationManager: LocationManager
    let geolocationDataProperty = MutableProperty<Geolocation?>(nil)
    let geolocationData: Signal<Geolocation?, NoError>

    init() {
        geolocationData = geolocationDataProperty.signal

        // Location Management
        locationManager = LocationManager()
        locationManager.delegate = self
        locationManager.requestLocation()
    }

    // MARK: - LocationManagerDelegate

    func didFindCurrentPosition(location: CLLocation) {
        geolocationDataProperty.value = Geolocation(location: location)
    }
}

视图控制器:

class MyViewController: UIViewController {
    let viewModel = MyViewModel()

    init() {
        super.init(nibName: nil, bundle: nil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        viewModel.geolocationData
            .observe(on: UIScheduler())
            .observeValues { geolocation in
                debugPrint("GOT GEOLOCATION")
        }
    }
}

可以使用 <~ 运算符创建来自任何类型的值流的绑定,但您可以开始按以下方式修改代码并查看它是否正常工作,它更容易调试 :-)

class MyViewModel: LocationManagerDelegate {
    let locationManager: LocationManager
    let geolocationDataProperty = MutableProperty<Geolocation?>(nil)

    init() {
        geolocationDataProperty.signal.observeValues { value in
            //use the value for updating the UI
        }

        // Location Management
        locationManager = LocationManager()
        locationManager.delegate = self
        locationManager.requestLocation()
    }

    // MARK: - LocationManagerDelegate

    func didFindCurrentPosition(location: CLLocation) {
        geolocationDataProperty.value = Geolocation(location: location)
    }
}

那么我们可以尝试使用二元运算符来实现 MVVM 模式,因为在模型视图中直接引用 UI 元素绝对不是一个好主意:-)

看看这个article,真有意思

我不确定你的地图组件是否直接支持响应式框架。

看看它有“.reactive”扩展名,如果它可以用于更新当前位置属性

如果存在,则可以使用 <~ 运算符编写类似于

的内容
map.reactive.position <~ viewModel.geolocationDataProperty

如果它没有响应式扩展,那么您只需将此代码移至 viewcontroller

viewModel.geolocationDataProperty.signal.observeValues { value in
                //use the value for updating the UI
            }

您已经有一个 Property 保存最新发出的值。不要使用 属性 的 signal,而是使用 producer。这样,当您启动 producer 时,您将首先获得当前值(在发送 none 时,您将获得 nil)。

比照。 the documentation:

The current value of a property can be obtained from the value getter. The producer getter returns a signal producer that will send the property’s current value, followed by all changes over time. The signal getter returns a signal that will send all changes over time, but not the initial value.

因此,关于问题中的代码,viewDidLoad 方法应该执行如下操作:

viewModel.geolocationDataProperty
        .producer
        .start(on: UIScheduler())
        .startWithValues { geolocation in
            debugPrint("GOT GEOLOCATION")
    }

如果您的问题是修改后的旧值。您可以尝试使用 Key-Value Observing 。添加您的 属性 以进行价值观察,例如

 geolocationDataProperty.addObserver(self, forKeyPath: "value", options: [.new, .old], context: &observerContext)

每当您的 geolocationDataProperty 被修改时,您将在委托方法中收到该值

 override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        let newValue = change?[.newKey] as? NSObject
         let oldValue = change?[.oldKey] as? NSObject
//Add your code
    }