4

我开始使用 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")
        }
    }
}
4

3 回答 3

5

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

参照。文档

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

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

viewModel.geolocationDataProperty
        .producer
        .start(on: UIScheduler())
        .startWithValues { geolocation in
            debugPrint("GOT GEOLOCATION")
    }
于 2017-07-05T06:53:08.437 回答
0

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

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 元素绝对是个坏主意 :-)

看看这篇文章,真的很有趣。

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

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

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

map.reactive.position <~ viewModel.geolocationDataProperty

如果它没有响应式扩展,那么您可以简单地将此代码移动到您的视图控制器中

viewModel.geolocationDataProperty.signal.observeValues { value in
                //use the value for updating the UI
            }
于 2017-07-03T08:42:02.660 回答
0

如果您的问题是在修改时具有旧值。您可以尝试使用 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
    }
于 2017-07-07T07:01:54.260 回答