2017-10-21 68 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) 
     } 
}