2017-02-12 117 views
1

我正在使用Firebase FirAuth API,并且在API返回结果之前,Disposables.create()已被返回并且不再可点击(我知道这可能是由于API之后没有observer.onCompleted叫。有没有办法等待它/听的结果?RxSwift回调首先返回结果

public func login(_ email: String, _ password: String) -> Observable<APIResponseResult> { 

    let observable = Observable<APIResponseResult>.create { observer -> Disposable in 

     let completion : (FIRUser?, Error?) -> Void = { (user, error) in 

      if let error = error { 
       UserSession.default.clearSession() 
       observer.onError(APIResponseResult.Failure(error)) 
       observer.on(.completed) 
       return 
      } 

      UserSession.default.user.value = user! 
      observer.onNext(APIResponseResult.Success) 
      observer.on(.completed) 
      return 
     } 

     DispatchQueue.main.async { 
      FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: completion) 
     } 

     return Disposables.create() 
    } 

    return observable 

} 
+0

火力地堡是异步的,目的不是要以同步的方式返回数据:

我通过捕捉错误,并传回的案件.success(MyType).error(Error)

例的enum解决它。虽然你可以强制这种模式,但会导致很多长期问题。所有的DispatchQueue和回调都应该被删除,否则它将成为一个噩梦来排除故障。让Firebase完成它的工作;一旦Firebase关闭内部的数据可用,然后继续进入用户界面的下一步,处理该数据等。代码可能过于复杂 - 也许如果您可以解释您正在尝试完成的内容,则明确的解决方案可能是提供而不是解决方法。 – Jay

+0

谢谢你的解释。我想要实现的是将正确的响应返回给视图控制器,以便重定向(如果成功)或发出警报(如果错误)。在这种情况下,我总是会得到一个空的错误,因为它总是首先返回错误场景 –

+0

只需更改流程:捕获用户信息,然后通过Firebase调用创建用户。在闭包内部,你可能会有一个错误(检查错误代码的原因),并告诉用户错误*或*没有错误,所以你可以继续显示下一个viewController或下一步是什么。应该是大约6行代码,并且可以在没有调度队列和回调的情况下完成。 – Jay

回答

1

你在你的假设是正确的,一个的onError/onCompletion事件终止序列可观察到,义,序列将不会发出任何更多事件,无论如何。

作为一个旁注,你不需要做.on(.completed)之后.onError(),因为onError已经终止了序列。

你写return Disposables.create()返回一个一次性的对象,以便观察到稍后可以添加到当DisposeBag被释放,将处理重新分配可观察到的一个DisposeBag的一部分,所以它应立即回报,但不会终止你的申请。

为了更好地理解所发生的事情,我会建议增加周围使用您可观察到的部分,这将让你完全了解哪些事件发生,将帮助您了解什么是错:)

+0

谢谢你指出。我想了解RxSwift如何与Firebase API协同工作,因此我正在尝试呼叫并等待响应。 –

0

.debug()声明前段时间有同样的问题,我想在onError中显示一个Alert,如果有一些错误,但没有处置可观察的。

// ApiResponseResult.swift 
enum ApiResponseResult { 
    case error(Error) 
    case success(FIRUser) 
} 

// ViewModel 
func login(...) -> Observable<ApiResponseResult> { 
    let observable = Observable.create { ... } 
    return observable.catchError { error in 
     return Observable<ApiResponseResult>.just(.error(error)) 
    } 
} 

// ViewController 
viewModel 
    .login 
    .subscribe(onNext: { result in 
     switch result { 
     case .error(let error): 
      // Alert or whatever 
      break 
     case .success(let user): 
      // Hurray 
      break 
     } 
    }) 
    .addDisposableTo(disposeBag)