2017-02-12 58 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)