Может ли наблюдатель сигнала получить доступ к последнему излученному значению сигнала ReactiveCocoa?
Я начинаю использовать 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")
}
}
}
3 ответа
У вас уже есть Property
который содержит последнее значение, выбрасываемое. Вместо использования свойства signal
использовать producer
, Таким образом, когда вы начинаете producer
сначала вы получите текущее значение (ни один не был отправлен, вы получите ноль).
Ср документация:
Текущее значение свойства можно получить из получателя значения. Получатель источника возвращает производителя сигнала , который отправит текущее значение свойства, а затем все изменения с течением времени. Получатель сигнала возвращает сигнал, который со временем будет отправлять все изменения, но не исходное значение.
Итак, что касается кода в вопросе, viewDidLoad
Метод должен сделать что-то вроде следующего:
viewModel.geolocationDataProperty
.producer
.start(on: UIScheduler())
.startWithValues { 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, поскольку иметь прямую ссылку на элемент пользовательского интерфейса внутри представления модели, безусловно, плохая идея:-)
Посмотрите на эту статью, это действительно интересно.
Я не уверен, поддерживает ли ваш компонент карты реактивную структуру.
увидеть, что он имеет расширение ".reactive" и может ли он использоваться для обновления свойства текущей позиции
если он присутствует, оператор <~ может использоваться для записи чего-то похожего на
map.reactive.position <~ viewModel.geolocationDataProperty
если у него нет реактивного расширения, вы можете просто переместить этот код в ваш viewcontroller
viewModel.geolocationDataProperty.signal.observeValues { value in
//use the value for updating the UI
}
Если ваша проблема заключается в том, чтобы иметь старое значение, когда оно будет изменено. Вы можете попробовать с наблюдением значения ключа. Добавьте вашу собственность для наблюдения за ценностями, например
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
}