Я использую библиотеку RSwift в своем приложении. Я пытаюсь получить местоположение пользователя, чтобы отправить его по сетевому запросу. Чтобы получить это местоположение, мне нужно использовать Observables, потому что функция должна выдать ошибку, если пользователь не разрешил местоположение.RxSwift и CLLocation: сбой при попытке получить местоположение пользователя
Этот алгоритм является частью конкатенированного массива многих Observables, запущенных в другом потоке, чем основной поток (чтобы не замораживать пользовательский интерфейс). Мне нужно, чтобы выполнить функцию «получить местоположение пользователя» в главном потоке, потому что, если не выполняется в главном потоке его падение и журнал крах:
fatal error: Executing on backgound thread. Please use `MainScheduler.instance.schedule` to schedule work on main thread
В приведенном выше коде, есть геолокации помощник инициализации (это singleton) и метод, выполненный для получения местоположения пользователя (или ошибки).
private var authorized: Observable<Bool?>
private var location: Observable<CLLocationCoordinate2D>
private let locationManager = CLLocationManager()
private init() {
locationManager.desiredAccuracy = LocationOptions.desiredAccuracy
authorized = Observable.just(false)
.map({ _ in CLLocationManager.authorizationStatus() })
.concat(locationManager.rx_didChangeAuthorizationStatus)
.distinctUntilChanged()
.map({ authorizedStatus in
switch authorizedStatus {
case .AuthorizedAlways, .AuthorizedWhenInUse:
return true
case .NotDetermined:
return nil
case .Restricted, .Denied:
return false
}
})
.catchErrorJustReturn(false)
location = locationManager.rx_didUpdateLocations
.filter { $0.count > 0 }
.map({ return $0.last!.coordinate })
}
func getLocation() -> Observable<Location> {
return authorized
.flatMap({ authorized -> Observable<CLLocationCoordinate2D> in
guard let authorized = authorized else {
self.locationManager.requestAlwaysAuthorization()
return Observable.empty()
}
if authorized {
self.startUpdating()
return self.location
} else {
return Observable.error(
NSError(
domain:"",
code: 0,
userInfo:nil)
)
}
})
// We just need one position updated
.take(1)
.map({ coordinate in
self.stopUpdating()
let location = Location(longitude: coordinate.longitude, latitude: coordinate.latitude, latestUpdatedDate: NSDate())
if location.isValid() {
saveLocation(location)
}
return location
})
.doOnError({ error in self.stopUpdating() })
}
Я вижу в RXSwift геолокации примере (https://github.com/ReactiveX/RxSwift/pull/429) класса, который может обрабатывать его с драйверами, но мне действительно нужно иметь ошибку и драйверы не могут возвращать ошибки.
Буду признателен, если кто-то может помочь мне в том, как этого добиться.
Я уже пытался добавить «.observeOn (MainScheduler.instance)» к 2 наблюдаемым, но он замораживает пользовательский интерфейс. Возможно, есть лучший способ сделать это без замораживания пользовательского интерфейса.
Благодаря
Спасибо за ваш ответ @sergdort. Я попробовал ваше предложение, но оно не сработало. Я также попытался только добавить '.observeOn (MainScheduler.instance)', но у меня также есть проблема «Выполнение на backgound thread». Когда я удаляю весь вызов кода Geolocation, он работает, и когда я добавляю только код, вызывающий 'rx_didChangeAuthorizationStatus', он сбой. По-видимому, это связано с этим методом. – romroll
Я нашел ту же проблему. Если Rx-код находится в обратном вызове locationManager (_ manager: CLLocationManager, didUpdateLocations location: [CLLocation]), функции observOn или subscribeOn не работают так, как мы ожидали, весь код выполняется только в основном потоке. Довольно странно – User9527