Ich verwende die RSwift-Bibliothek in meiner App. Ich versuche, den Benutzerstandort zu erhalten, um es in einer Netzwerkanforderung zu senden. Um diesen Standort zu erhalten, muss ich Observables verwenden, da die Funktion einen Fehler auslösen muss, wenn der Benutzer den Standort nicht autorisiert hat.RxSwift und CLLocation: Absturz beim Versuch, den Benutzerstandort zu ermitteln
Dieser Algorithmus ist ein Teil eines verketteten Arrays vieler Observables, die in einem anderen Thread als dem Hauptthread ausgeführt wurden (um die UI nicht einzufrieren). Ich brauche die „get Benutzerstandort“ -Funktion in dem Haupt-Thread ausgeführt werden, da, wenn nicht im Hauptthread ausgeführt es zum Absturz bringen und das Crash-Protokoll ist:
fatal error: Executing on backgound thread. Please use `MainScheduler.instance.schedule` to schedule work on main thread
In dem obigen Code gibt den Geolocation Helfer init ist (Dies ist ein Singleton) und die Methode ausgeführt, um den Benutzerstandort (oder einen Fehler) zu erhalten.
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() })
}
Ich sehe in dem RXSwift Geolocation Beispiel (https://github.com/ReactiveX/RxSwift/pull/429) eine Klasse, die es mit Treibern umgehen kann, aber ich brauche wirklich einen Fehler und Treiber haben, kann keine Fehler zurück.
Ich würde mich freuen, wenn mir jemand helfen kann, dies zu erreichen.
Ich habe bereits versucht, ".observeOn (MainScheduler.instance)" zu den 2 Observablen hinzuzufügen, aber es friert die UI ein ... vielleicht gibt es einen besseren Weg, dies ohne Einfrieren der UI zu tun.
Dank
Danke für Ihre Antwort @sergdort. Ich habe deinen Vorschlag ausprobiert, aber es hat nicht funktioniert. Ich habe auch versucht, nur das '.observeOn (MainScheduler.instance)' hinzuzufügen, aber ich habe auch das Problem "Executing on backgound thread". Wenn ich den Aufruf des Geolocation-Codes lösche, funktioniert es, und wenn ich nur den Code hinzufüge, der den 'rx_didChangeAuthorizationStatus' aufruft, stürzt er ab. Es scheint wirklich mit dieser Methode verbunden zu sein. – romroll
Ich habe das gleiche Problem gefunden. Wenn sich der Rx-Code im Callback von locationManager (_manager: CLLocationManager, didUpdateLocations: [CLLocation]) befindet, funktionieren observeOn oder subscribeOn nicht wie erwartet. Der gesamte Code wird nur im Hauptthread ausgeführt. Recht seltsam – User9527