2016-04-22 39 views
1

我在我的应用程序中使用RSwift库。我正在尝试获取用户位置以便通过网络请求发送它。为了得到这个位置,我需要使用Observables,因为在用户没有授权位置的情况下,该函数必须抛出一个错误。RxSwift和CLLocation:尝试获取用户位置时崩溃

这个算法是许多观察对象的连接数组的一部分,它在主线程之外的另一个线程中运行(为了不冻结UI)。我需要在主线程中执行“获取用户位置”功能,因为如果不能在主线程中执行它崩溃,崩溃日志是:

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

在上面的代码中,有地理位置帮手的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)可以与驱动程序处理它的一类,但我真的需要有一个错误,驱动程序无法返回错误。

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

我已经尝试添加“.observeOn(MainScheduler.instance)”到2个observable,但它冻结了用户界面..也许有更好的方法来做到这一点,而不会冻结用户界面。

感谢

回答

0

@romroll,DelegateProxy只在主线程工作在RxCocoa现在。 试着做这样的事

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

希望,这有助于。 如果没有,你可以随时找到我在RxSwiftSlack,通过提@sergdort,还是别人:)

+1

感谢您的回复@sergdort。我尝试了你的建议,但没有奏效。我也尝试只添加'.observeOn(MainScheduler.instance)',但我也有“在后台线程上执行”问题。当我删除所有的地理位置代码调用时,它会起作用,当我只添加调用'rx_didChangeAuthorizationStatus'的代码时,它会崩溃。这似乎与这种方法有关。 – romroll

+0

我发现相同的问题。如果Rx代码位于locationManager(_ manager:CLLocationManager,didUpdateLocations位置:[CLLocation])的回调中,observeOn或subscribeOn不能按照我们的预期工作,所有代码仅在主线程中执行。很奇怪 – User9527

0

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

相关问题