2016-04-22 3 views
1

私のアプリでRSwiftライブラリを使用しています。私はネットワーク要求でそれを送信するためにユーザーの場所を取得しようとしています。この場所を取得するには、Observablesを使用する必要があります。これは、ユーザーが場所を承認しなかった場合にエラーをスローする必要があるためです。RxSwiftとCLLocation:ユーザーの場所を取得しようとするとクラッシュします

このアルゴリズムは、(UIをフリーズさせないために)メインスレッドよりも別のスレッドで実行されたObservableの連結配列の一部です。 (

上記のコードで
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)ドライバとそれを扱うことができるクラスで見たが、私は実際にエラーを返すことができないエラーとドライバを持っている必要があります。

これを達成する方法についてお手伝いいただければ幸いです。

私は既に2つの観測値に ".observeOn(MainScheduler.instance)"を追加しようとしましたが、UIがフリーズしています。UIをフリーズすることなくこれを行うより良い方法があります。

おかげで今のRxCocoaにメインスレッド上でのみ動作しますDelegateProxy

答えて

0

@romroll、。 この

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

希望のような何かをしようとすると、このことができます。 ない場合は、常にそれが、もはやとしてプロジェクトに拡張CLLocationManager + Rx.swiftとRxCLLocationManagerDelegateProxy.swiftをコピーする必要が@sergdort、または他の誰か:)

+1

お返事ありがとうございました@sergdort。私はあなたの提案を試みたが、うまくいかなかった。私も '.observeOn(MainScheduler.instance)'だけを追加しようとしましたが、 "バックグラウンドスレッドで実行する"問題もあります。ジオロケーションコードの呼び出しをすべて削除すると動作し、 'rx_didChangeAuthorizationStatus'を呼び出すコードだけを追加するとクラッシュします。これは本当にこの方法に関連しているようです。 – romroll

+0

同じ問題が見つかりました。 RxコードがlocationManager(_ manager:CLLocationManager、didUpdateLocations locations:[CLLocation])のコールバックにある場合、observeOnまたはsubscribeOnは期待通りに機能しません。すべてのコードはメインスレッドだけで実行されます。かなり奇妙 – User9527

0

を言及することで、RxSwiftSlackで私に達することができますRxCocoaの一部

関連する問題