Generic Decodable 无需解码
Generic Decodable without decoding
我正在使用一种通用方法来解码 JSONAlamoFire 生成的响应。我的功能如下:
private func fetch<T: Swift.Decodable>(URLRequest: URLRequestConvertible) -> SignalProducer<T, NetworkError> {
return Network.request(URLRequest)
.attemptMap { JSON in
do {
let jsondata = try JSONSerialization.data(withJSONObject: JSON as! [String:Any], options: .prettyPrinted)
return .success(try JSONDecoder().decode(T.self, from: jsondata))
} catch let error {
Logger.shared.error("Error while decoding a JSON", error: error as NSError, userInfo: ["json" : JSON, "urlRequest" : URLRequest.urlRequest!.debugDescription])
return .failure(.incorrectDataReturned)
}
}
}
对于我的每个请求,我都创建了一个遵循 Decodable 协议的结构。
对于一个请求,我不想解码 JSON 因为它的结构很复杂而且因为我只需要在另一个请求中发回它,我只想将响应保存在一个结构中像这样的例子:
struct GenericResponse: Swift.Decodable {
let data: Data
}
其中数据是响应。所以,我只想获取响应并将其放入结构中而不进行进一步解码。
是否可以不破坏我的功能的通用性?如果 T.self 是某种类型,他们是否可以构建不解码的解码器?
我不太明白你想达到什么目的。但是我遇到了需要使用泛型解码的情况。
这就是我编写 DecoderHelper class 的原因,它使我能够解码通用数组或通用对象(取决于您的 JSON 响应)。
也许它可以启发你,你会发现如何优化它或了解你的situation/issue。
final class DecoderHelper {
static func decodeGenericObject<T: Decodable>(data: Data, completion : (Result<T, ErrorResult>) -> Void) {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(T.self, from: data)
completion(Result.success(decodedData))
} catch {
completion(Result.failure(.decoder(error: error)))
}
}
static func decodeGenericArray<T: Decodable>(data: Data, completion : (Result<[T], ErrorResult>) -> Void) {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode([T].self, from: data)
completion(Result.success(decodedData))
} catch {
completion(Result.failure(.decoder(error: error)))
}
}
}
PS: 为什么要发送给其他请求因为 "the JSON structure is too complex" ?
现在使用 Codable 协议解析 JSON 文件非常简单。
尝试一下并训练自己,既然我已经习惯了,我喜欢解析 JSON。
如果您想避免对特定响应进行解码,您可以重载 fetch
函数来处理这种情况。
请参阅以下示例,其中第二次提取 method
被重载以将响应数据保存在结构中,而不是经过解码过程。
typealias JSON = [String: Any]
protocol RawResponse {
init(data: Data)
}
// 1
func fetch<T: Decodable>(json: JSON) -> T? {
guard let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []),
let response = try? JSONDecoder().decode(T.self, from: jsonData) else {
return nil
}
return response
}
// 2
func fetch<T: RawResponse>(json: JSON) -> T? {
guard let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) else {
return nil
}
return T(data: jsonData)
}
有了这个重载,如果响应 struct
符合 RawResponse
而不是 Decodable
(因为我们不需要实际解码数据), fetch
过载被触发。
struct UserResponse: Decodable {
var username: String
}
let userJson: JSON = [
"username": "someUser"
]
let user: UserResponse? = fetch(json: userJson) // call fetch #1
user?.username // someUser
struct GenericResponse: RawResponse {
var data: Data
}
let notParsable: JSON = [
"someKey": "someValue"
]
let rawData: GenericResponse? = fetch(json: notParsable) // call fetch #2
rawData?.data // 23 bytes
我正在使用一种通用方法来解码 JSONAlamoFire 生成的响应。我的功能如下:
private func fetch<T: Swift.Decodable>(URLRequest: URLRequestConvertible) -> SignalProducer<T, NetworkError> {
return Network.request(URLRequest)
.attemptMap { JSON in
do {
let jsondata = try JSONSerialization.data(withJSONObject: JSON as! [String:Any], options: .prettyPrinted)
return .success(try JSONDecoder().decode(T.self, from: jsondata))
} catch let error {
Logger.shared.error("Error while decoding a JSON", error: error as NSError, userInfo: ["json" : JSON, "urlRequest" : URLRequest.urlRequest!.debugDescription])
return .failure(.incorrectDataReturned)
}
}
}
对于我的每个请求,我都创建了一个遵循 Decodable 协议的结构。
对于一个请求,我不想解码 JSON 因为它的结构很复杂而且因为我只需要在另一个请求中发回它,我只想将响应保存在一个结构中像这样的例子:
struct GenericResponse: Swift.Decodable {
let data: Data
}
其中数据是响应。所以,我只想获取响应并将其放入结构中而不进行进一步解码。
是否可以不破坏我的功能的通用性?如果 T.self 是某种类型,他们是否可以构建不解码的解码器?
我不太明白你想达到什么目的。但是我遇到了需要使用泛型解码的情况。
这就是我编写 DecoderHelper class 的原因,它使我能够解码通用数组或通用对象(取决于您的 JSON 响应)。
也许它可以启发你,你会发现如何优化它或了解你的situation/issue。
final class DecoderHelper {
static func decodeGenericObject<T: Decodable>(data: Data, completion : (Result<T, ErrorResult>) -> Void) {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(T.self, from: data)
completion(Result.success(decodedData))
} catch {
completion(Result.failure(.decoder(error: error)))
}
}
static func decodeGenericArray<T: Decodable>(data: Data, completion : (Result<[T], ErrorResult>) -> Void) {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode([T].self, from: data)
completion(Result.success(decodedData))
} catch {
completion(Result.failure(.decoder(error: error)))
}
}
}
PS: 为什么要发送给其他请求因为 "the JSON structure is too complex" ?
现在使用 Codable 协议解析 JSON 文件非常简单。
尝试一下并训练自己,既然我已经习惯了,我喜欢解析 JSON。
如果您想避免对特定响应进行解码,您可以重载 fetch
函数来处理这种情况。
请参阅以下示例,其中第二次提取 method
被重载以将响应数据保存在结构中,而不是经过解码过程。
typealias JSON = [String: Any]
protocol RawResponse {
init(data: Data)
}
// 1
func fetch<T: Decodable>(json: JSON) -> T? {
guard let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []),
let response = try? JSONDecoder().decode(T.self, from: jsonData) else {
return nil
}
return response
}
// 2
func fetch<T: RawResponse>(json: JSON) -> T? {
guard let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) else {
return nil
}
return T(data: jsonData)
}
有了这个重载,如果响应 struct
符合 RawResponse
而不是 Decodable
(因为我们不需要实际解码数据), fetch
过载被触发。
struct UserResponse: Decodable {
var username: String
}
let userJson: JSON = [
"username": "someUser"
]
let user: UserResponse? = fetch(json: userJson) // call fetch #1
user?.username // someUser
struct GenericResponse: RawResponse {
var data: Data
}
let notParsable: JSON = [
"someKey": "someValue"
]
let rawData: GenericResponse? = fetch(json: notParsable) // call fetch #2
rawData?.data // 23 bytes