2017-02-23 90 views
0

我有一個快速的問題:如何映射RxSwift觀察到的,結果

  • 我有一個返回Observable<Result<String, RequestError>>網絡請求,我們稱之爲requestToken
  • 如果此請求成功,我想用String(令牌)做返回Observable<Result<NSDictionary, RequestError>>另一個請求,讓我們把它requestData
  • 當第二個請求回來,我想令牌合併到它的字典
  • 在我要地圖結束從Observable<Result<String, RequestError>>Observable<Result<NSDictionary, RequestError>>

我怎樣才能做到這一點沒有在我的代碼多重嵌套層次?

這就是我今天:

requestToken() 
    .flatMap({ result -> Observable<Result<NSDictionary, RequestError>> in 
     switch result { 
     case .success(let token): 
      return requestData(token: token).map({ $0.map({ $0 + ["token": token] }) }) 
     case .failure(let error): 
      return Observable.of(.failure(error)) 
     } 
    }) 
+0

是否有你手動返回錯誤結果而不是使用內置錯誤系統的原因? –

+0

對於類型系統。我需要處理'RequestError'和來自'Observable'的錯誤系統只會給我一個通用的'Error'。 'throw'語法也是如此,它們都沒有給出我可以在函數簽名中發生哪些錯誤的文檔。 –

回答

0

如果您使用內置的錯誤系統,你可以保存自己無需手動傳遞錯誤沿和所有這將產生開關。你可以在最後拋出錯誤。

我會做更多的事情是這樣的:

// this is necessary to handle adding the token to the dictionary. 
extension Dictionary { 

    /// An immutable version of update. Returns a new dictionary containing self's values and the key/value passed in. 
    func updatedValue(_ value: Value, forKey key: Key) -> Dictionary<Key, Value> { 
     var result = self 
     result[key] = value 
     return result 
    } 
} 

// function signatures, note that they don't return Results anymore. 
func requestToken() -> Observable<String> { /*...*/ } 
func requestData(withToken: String) -> Observable<[String: Any]> { /*...*/ } 

requestToken().flatMapLatest { 
    requestData(token: $0) 
     .map { $0.updatedValue($0, forKey: "token") } 
     .map { .success($0) } 
}.catchError { 
     Observable.just(.failure($0 as! RequestError)) 
} 

通過以上,最終的結果將是一個Observable<Result<[String: Any], RequestError>>就像在你的情況,但錯誤處理乾淨多了。

如果你不能改變你正在使用,則這兩個函數簽名我會做到這一點:

func throwError<T, U: Error>(result: Result<T, U>) throws -> T { 
     switch result { 
     case .success(let token): 
      return token 
     case .failure(let error): 
      throw error 
     } 
    } 

    requestToken().map { 
     try throwError(result: $0) 
    }.flatMapLatest { 
     requestData(token: $0) 
      .map { try throwError(result: $0) } 
      .map { $0.updatedValue($0, forKey: "token") } 
    } 
    .map { .success($0) } 
    .catchError { 
     Observable.just(.failure($0 as! RequestError)) 
    } 
2

更新時間:

這是一個詳細的例子,希望這可以幫助:

enum RequestError: Error { 
    case unknown 
} 

func requestToken() -> Observable<String> { 

    return Observable.create { observer in 

     let success = true 

     if success { 
      observer.onNext("MyTokenValue") 
      observer.onCompleted() 
     } else { 
      observer.onError(RequestError.unknown) 
     } 

     return Disposables.create() 
    } 
} 

func requestData(token: String) -> Observable<[String: Any]> { 

    return Observable<[String: Any]>.create { observer in 

     let success = false 

     if success { 
      observer.onNext(["uid": 007]) 
      observer.onCompleted() 
     } else { 
      observer.onError(RequestError.unknown) 
     } 

     return Disposables.create() 
    } 
    .map { (data: [String: Any]) in 
     var newData = data 
     newData["token"] = token 
     return newData 
    } 
} 


requestToken()      //() -> Observable<String> 
    .flatMapLatest(requestData)  // Observable<String> -> Observable<[String: Any]> 
    .materialize()     // Observable<[String: Any]> -> Observable<Event<[String: Any]>> 
    .subscribe(onNext: { event in 
     switch event { 
     case .next(let dictionary): 
      print("onNext:", dictionary) 
     case .error(let error as RequestError): 
      print("onRequestError:", error) 
     case .error(let error): 
      print("onOtherError:", error) 
     case .completed: 
      print("onCompleted") 
     } 
    }) 
    .disposed(by: disposeBag) 

原文:

我覺得它更容易使用來實現它用更少的額外的工作:

func requestToken() -> Observable<String> { return .empty() } 
func requestData(token: String) -> Observable<NSDictionary> { return .empty() } 
enum RequestError: Error {} 

requestToken() 
    .flatMapLatest(requestData) 
    .materialize() 
    .subscribe(onNext: { event in 
     switch event { 
     case .next(let dictionary): 
      print("onNext:", dictionary) 
     case .error(let error as RequestError): 
      print("onRequestError:", error) 
     case .error(let error): 
      print("onOtherError:", error) 
     case .completed: 
      print("onCompleted") 
     } 
    }) 
    .disposed(by: disposeBag) 

希望這有助於。

+0

我在Observable上找不到'materialize()'。它是否出現在3.0版本上? –

+0

是的,它從3.4.0版開始可用https://github.com/ReactiveX/RxSwift/releases/tag/3.4.0 – beeth0ven

+0

我不確定我是否理解'materialize'的用途,首先,我的'requestToken'返回一個'Result',而不是'String',所以我不能'.flatMapLatest(requestData)'。其次,我需要將token與'requestData'的結果字典進行合併。你能澄清嗎? –