2017-10-21 72 views
0

我試圖使用JSONDecoder來解碼從我的服務器使用Alamofire json響應。當我用guard解碼響應時,它沒有任何問題。這種方法的副作用是我無法分辨解碼實際上失敗時的問題。捕獲模式更改回調簽名

guard let result: TResponseData = try? decoder.decode(TResponseData.self, from: response.data!) else { 
    self.logger.error("Unable to decode the response data into a model representation.") 
    return 
} 

所以不是我想要用do { } catch { },但我想不出我應該如何準確的Alamofire responseJSON回調中使用它。

這就是我目前有:

Alamofire.request(completeUrl, method: .post, parameters: parameters, encoding: encoding, headers: headers) 
.validate() 
.responseJSON { (response) -> Void in 
    self.logger.info("POST Response: \(String(describing:response.response?.statusCode))") 
    switch response.result { 
    case .success(_): 
     let decoder = JSONDecoder() 
     decoder.dateDecodingStrategy = .custom(Date.toTMDBDate) 

     do { 
      let _ = try decoder.decode(TResponseData.self, from: response.data!) 
     } catch DecodingError.dataCorrupted(let error) { 
      self.logger.error(error.underlyingError) 
      return 
     } 

     completion(result) 
     return 
    case .failure(let error): 
     //.... 
    } 

我這個代碼給然而什麼是對.responseJSON { (response) -> Void in行編譯錯誤。

將類型爲'(_) - > Void'的投擲函數轉換爲非拋出函數類型'(DataResponse) - > Void'無效轉換。

警衛代碼工作正常,如果我改變trytry?或強制拆開包裝,它編譯 - 我只是不明白這有我的捕捉處理實際的錯誤。

如果我更改catch塊,以便它不包含任何模式,則代碼將進行編譯。

catch { 
    return 
} 

這並不能告訴我什麼,我的guard給了我什麼。我真的想要捕獲decode操作遇到的錯誤。我是否使用了錯誤的模式?爲什麼使用DecodingError.dataCorrupted模式似乎會改變回調簽名?

+0

真棒謝謝! –

+1

嗨,@哈米什,你爲什麼不把這個作爲答案來寫,所以約翰遜可以將它標記爲這樣! – leanne

+0

@leanne現在就完成了:) – Hamish

回答

1

JSONDecoder可以拋出除DecodingError.dataCorrupted以外的錯誤;你需要能夠處理被拋出的任意Error的情況。所以,如果你想處理這個錯誤,你需要一個無條件的catch {}塊。

你還可以:

  • 使用responseData而不是responseJSON當您與JSONDecoder做你自己deserialisation。
  • 如果需要,請在Alamofire的Result類型上使用unwrap()方法,以便將網絡錯誤與解碼錯誤合併。

這是什麼樣子:

Alamofire 
    .request(
     completeUrl, method: .post, parameters: parameters, 
     encoding: encoding, headers: headers 
    ) 
    .validate() 
    .responseData { response in 

     self.logger.info(
      "POST Response: \(response.response?.statusCode as Any)" 
     ) 

     let decoder = JSONDecoder() 
     decoder.dateDecodingStrategy = .custom(Date.toTMDBDate) 

     do { 
      let result = try decoder.decode(
       TResponseData.self, from: response.result.unwrap() 
      ) 
      completion(result) 
     } catch { 
      self.logger.error(error) 
     } 
    } 

儘管這裏有一點要注意的是,你不打電話completion如果請求失敗;我會親自改變這種做法,並通過使completion參數爲Result<TResponseData>來傳播錯誤。

在這種情況下,你可以使用ResultflatMap(_:)方法,而不是unwrap()catch {}塊:

func doRequest(_ completion: @escaping (Result<TResponseData>) -> Void) { 

    let completeURL = // ... 
    let parameters = // ... 
    let encoding = // ... 
    let headers =  // ... 

    Alamofire 
     .request(
      completeURL, method: .post, parameters: parameters, 
      encoding: encoding, headers: headers 
     ) 
     .validate() 
     .responseData { response in 

      self.logger.info(
       "POST Response: \(response.response?.statusCode as Any)" 
      ) 

      let decoder = JSONDecoder() 
      decoder.dateDecodingStrategy = .custom(Date.toTMDBDate) 

      // if response.result is successful data, try to decode. 
      // if decoding fails, result is that error. 
      // if response.result is failure, result is that error. 
      let result = response.result.flatMap { 
       try decoder.decode(TResponseData.self, from: $0) 
      } 
      .ifFailure { 
       self.logger.error($0) 
      } 

      completion(result) 
     } 
}