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

时间:2017-06-28 22:09:38

标签: ios swift reactive-programming reactive-cocoa reactive-cocoa-5

我开始使用ReactiveCocoa,我仍在努力解决一些基本概念:

  1. 我的应用程序开始侦听地理位置数据(我的视图模型中为init
  2. 我的应用程序发出一个包含当前位置的信号(didFindCurrentPosition被调用)
  3. 我的视图控制器显示地图加载(viewDidLoad在我的视图控制器中)
  4. 我的视图控制器开始观察当前位置信号(仍为viewDidLoad
  5. 我的问题是:在完成第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")
            }
        }
    }
    

3 个答案:

答案 0 :(得分:4)

您已经拥有一个Property来保存最新的值。而不是使用属性signal使用producer。这样当你启动producer时,你将首先得到当前值(没有发送,你将得到零)。

比照。 the documentation

  

可以从值getter获取属性的当前值。生产者getter返回一个信号生成器,它将发送属性的当前值,随后是所有随时间变化的。信号获取器返回一个信号,该信号将随时间发送所有变化,但不是初始值

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

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

答案 1 :(得分:0)

可以使用&lt;〜运算符来设置来自任何类型的值的绑定,但是您可以按照以下方式开始修改代码并看到它工作正常,它更容易调试: - )

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”扩展名,如果它可用于更新当前位置属性

如果它存在,那么&lt;〜运算符可以用来写类似于

的东西
map.reactive.position <~ viewModel.geolocationDataProperty

如果它没有反应式扩展,那么您只需在viewcontroller中移动此代码

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

答案 2 :(得分:0)

如果您的问题是在修改后有旧值。您可以尝试使用键值观察。添加您的属性以进行值观察,如

 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
    }