【问题标题】:RxSwift and CLLocation : crash when trying to get user locationRxSwift 和 CLLocation :尝试获取用户位置时崩溃
【发布时间】:2016-08-16 09:54:06
【问题描述】:

我在我的应用程序中使用 RSwift 库。我正在尝试获取用户位置以便在网络请求中发送它。要获取这个位置,我需要使用 Observables,因为如果用户没有授权位置,该函数必须抛出错误。

该算法是在主线程之外的另一个线程中运行的许多 Observable 的串联数组的一部分(为了不冻结 UI)。我需要在主线程中执行“获取用户位置”功能,因为如果不在主线程中执行它会崩溃并且崩溃日志是:

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

在上面的代码中,有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() })
}

我在 RXSwift 地理定位示例 (https://github.com/ReactiveX/RxSwift/pull/429) 中看到了一个可以使用 Drivers 处理它的类,但我确实需要有一个错误并且 Drivers 不能返回错误。

如果有人可以帮助我实现这一目标,我将不胜感激。

我已经尝试将“.observeOn(MainScheduler.instance)”添加到 2 个可观察对象,但它会冻结 UI。也许有更好的方法可以在不冻结 UI 的情况下执行此操作。

谢谢

【问题讨论】:

    标签: ios swift multithreading cllocationmanager rx-swift


    【解决方案1】:

    @romroll, DelegateProxy 目前仅适用于 RxCocoa 的主线程。 尝试做这样的事情

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

    希望,这会有所帮助。 如果没有,您可以随时通过@sergdort 或其他人通过RxSwiftSlack 与我联系:)

    【讨论】:

    • 感谢您的回复@sergdort。我试过你的建议,但没有奏效。我也尝试只添加.observeOn(MainScheduler.instance),但我也有“在后台线程上执行”问题。当我删除所有地理定位代码调用时,它可以工作,而当我只添加调用rx_didChangeAuthorizationStatus 的代码时,它会崩溃。好像真的和这个方法有关。
    • 我发现了同样的问题。如果 Rx 代码在 locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) 的回调中,则 observeOn 或 subscribeOn 没有像我们预期的那样工作,所有代码都在主线程中执行。很奇怪
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多