简体   繁体   English

RxSwift和CLLocation:尝试获取用户位置时崩溃

[英]RxSwift and CLLocation : crash when trying to get user location

I am using RSwift library in my app. 我在我的应用程序中使用RSwift库。 I am trying to get the user location in order to send it in a network request. 我试图获取用户位置,以便在网络请求中发送它。 To get this location, I need to use Observables because the function must throw an error in case of user did not authorize location. 要获取此位置,我需要使用Observables,因为该函数必须在用户未授权位置时抛出错误。

This algorithm is a part of a concatenated array of many Observables ran in an another thread than the main thread (in order to not freeze the UI). 此算法是在主线程之外的另一个线程中运行的许多Observable的连接数组的一部分(为了不冻结UI)。 I need to execute the "get user location" function in the main thread because if not executed in the main thread it crash and the crash log is : 我需要在主线程中执行“获取用户位置”功能,因为如果没有在主线程中执行它崩溃,崩溃日志是:

fatal error: Executing on backgound thread. Please use `MainScheduler.instance.schedule` to schedule work on main thread

In the above code, there is the geolocation helper init (this is a singleton) and the method executed to get the user location (or an error). 在上面的代码中,有一个geolocation helper init(这是一个单例),并执行该方法来获取用户位置(或错误)。

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() })
}

I see in the RXSwift geolocation example ( https://github.com/ReactiveX/RxSwift/pull/429 ) a class that can handle it with Drivers but I really need to have an error and Drivers cannot return errors. 我在RXSwift地理位置示例( https://github.com/ReactiveX/RxSwift/pull/429 )中看到了一个可以使用Drivers处理它的类但我确实需要出错并且驱动程序无法返回错误。

I would appreciate if someone can help me on how to achieve this. 如果有人能帮我解决这个问题,我将不胜感激。

I already tried to add " .observeOn(MainScheduler.instance) " to the 2 observables but it freezes the UI.. maybe there is a better way to do this without freezing UI. 我已经尝试将“.observeOn(MainScheduler.instance)”添加到2个observable中,但它冻结了UI ..也许有更好的方法来做到这一点而不冻结UI。

Thanks 谢谢

@romroll, DelegateProxy works only on Main thread in RxCocoa for now. @romroll, DelegateProxy现在只适用于RxCocoa中的主线程。 Try to do something like this 尝试做这样的事情

.map({ _ in CLLocationManager.authorizationStatus() })
        .observeOn(MainScheduler.instance)
        .concat(locationManager.rx_didChangeAuthorizationStatus)
        .observeOn(someOtherScheduler)
        .distinctUntilChanged()

Hope, this helps. 希望这可以帮助。 If not, you can always reach me in the RxSwiftSlack , by mentioning @sergdort, or somebody else :) 如果没有,你可以随时通过提及@sergdort或其他人在RxSwiftSlack中与我联系:)

您必须将扩展CLLocationManager + Rx.swift和RxCLLocationManagerDelegateProxy.swift复制到您的项目,因为它不再是RxCocoa的一部分

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM