信号观察者能否访问 ReactiveCocoa 信号的最后发射值?
Can a signal observer get access to the last emitted value of a ReactiveCocoa signal?
我开始使用 ReactiveCocoa,但我仍在为一些基本概念而苦苦挣扎:
- 我的应用程序开始侦听地理位置数据(
init
在我的视图模型中)
- 我的应用程序发出带有我当前位置的信号(
didFindCurrentPosition
被调用)
- 我的视图控制器显示地图加载(
viewDidLoad
在我的视图控制器中)
- 我的视图控制器开始观察当前位置信号(仍然
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
}
我开始使用 ReactiveCocoa,但我仍在为一些基本概念而苦苦挣扎:
- 我的应用程序开始侦听地理位置数据(
init
在我的视图模型中) - 我的应用程序发出带有我当前位置的信号(
didFindCurrentPosition
被调用) - 我的视图控制器显示地图加载(
viewDidLoad
在我的视图控制器中) - 我的视图控制器开始观察当前位置信号(仍然
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
}