捕获模式更改回调签名
Catch pattern changes callback signature
我正在尝试使用 JSONDecoder
解码来自我的服务器的 json 响应,使用 Alamofire。当我用 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
行的编译器错误。
Invalid conversion from throwing function of type '(_) -> Void' to non-throwing function type '(DataResponse) -> Void'.
保护代码工作正常,如果我将 try
更改为 try?
或强制解包,它会编译 - 我只是无法让我的 catch 处理实际错误.
如果我更改 catch
块使其不包含任何模式,则代码会编译。
catch {
return
}
与 guard
给我的东西相比,这并没有给我带来任何好处。我真的很想捕获 decode
操作遇到的错误。我使用了错误的模式吗?为什么使用 DecodingError.dataCorrupted
模式似乎会更改回调签名?
JSONDecoder
可以抛出 DecodingError.dataCorrupted
以外的错误;您需要能够处理 arbitrary Error
被抛出的情况。所以,如果你想处理那个错误,你需要一个无条件的 catch {}
块。
您还可以:
- 使用
responseData
而不是 responseJSON
,因为您正在使用 JSONDecoder
进行自己的反序列化。
- 在 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>
参数来传播错误。
在这种情况下,您可以使用 Result
的 flatMap(_:)
方法而不是 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: [=11=])
}
.ifFailure {
self.logger.error([=11=])
}
completion(result)
}
}
我正在尝试使用 JSONDecoder
解码来自我的服务器的 json 响应,使用 Alamofire。当我用 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
行的编译器错误。
Invalid conversion from throwing function of type '(_) -> Void' to non-throwing function type '(DataResponse) -> Void'.
保护代码工作正常,如果我将 try
更改为 try?
或强制解包,它会编译 - 我只是无法让我的 catch 处理实际错误.
如果我更改 catch
块使其不包含任何模式,则代码会编译。
catch {
return
}
与 guard
给我的东西相比,这并没有给我带来任何好处。我真的很想捕获 decode
操作遇到的错误。我使用了错误的模式吗?为什么使用 DecodingError.dataCorrupted
模式似乎会更改回调签名?
JSONDecoder
可以抛出 DecodingError.dataCorrupted
以外的错误;您需要能够处理 arbitrary Error
被抛出的情况。所以,如果你想处理那个错误,你需要一个无条件的 catch {}
块。
您还可以:
- 使用
responseData
而不是responseJSON
,因为您正在使用JSONDecoder
进行自己的反序列化。 - 在 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>
参数来传播错误。
在这种情况下,您可以使用 Result
的 flatMap(_:)
方法而不是 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: [=11=])
}
.ifFailure {
self.logger.error([=11=])
}
completion(result)
}
}