将 json 解码为通用数组或 swift 中的 class
decoding a json to generic array or class in swift
如何将 json 解码为 swift 中的通用模型?
在 java 解码 json 中,我使用 GSON,一般来说,我使用 <T<E>> or ArrayList<E>
并不重要。在 swift 中,数组是一个结构,不能继承,它有未实现可解码。
我正在寻找一个通用的优雅 class 用于我所有的网络服务。
我的场景:
我有 json 回复
{
"status": true,
"message": "",
"code": 200,
"response": [{
"id": 43
}]
}
以及来自 Web 服务的通用响应模型:
class GeneralResponse< T : Decodable >:NSObject,Decodable{
var status = false
var message = ""
var code = -1
var response : T?
private enum CodingKeys: String, CodingKey {
case status
case message
case code
case response
}
required public init(from decoder: Decoder) throws{
let container = try decoder.container(keyedBy: CodingKeys.self)
status = try container.decode(Bool.self, forKey: .status)
message = try container.decode(String.self, forKey: .message)
code = try container.decode(Int.self, forKey: .code)
response = try container.decode(T.self, forKey: .response)
}
}
class ItemDemoModel:Decodable {
var id = -1
private enum ItemDemModelCodingKeys : String, CodingKey {
case id
}
required init(from decoder:Decoder) throws {
let container = try decoder.container(keyedBy: ItemDemModelCodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
}
}
响应变量可以是 ItemDemoModel 或 ItemDemoModel 数组。
例如:
可以是GeneralResponse<Array<ItemDemoModel>>>
或 GeneralResponse<ItemDemoModel>>
谢谢。
如果 Array<T>
符合 Decodable
如果 T
符合 Decodable
,那么 GeneralResponse<[ItemDemoModel]>
不会产生任何错误。
如图所示:
您可以简单地这样做:
let decoder = JSONDecoder()
let obj = try decoder.decode(type, from: json.data(using: .utf8)!)
如果你声明一个 Decodable
属性与 json
中的键同名,那么你真的不需要 enum
来定义 Coding
键和一个使用密钥手动映射每个 属性 的初始化程序。
此外,没有必要从 NSObject
in Swift
继承,除非你有一个特定的用例。查看声明,似乎没有必要,所以您的 GeneralResponse
可以像这样简单地重新声明,
class GeneralResponse<T: Decodable>: Decodable {
var code: Int
var status: Bool
var message: String?
var response : T?
}
同理,ItemDemoModel
可以这样声明,
class ItemDemoModel: Decodable {
var id: Int
}
现在您可以按如下方式设置您的服务以获得任何请求的 GeneralResponse<T>
,
struct RequestObject {
var method: String
var path: String
var params: [String: Any]
}
class WebService {
private let decoder: JSONDecoder
public init(_ decoder: JSONDecoder = JSONDecoder()) {
self.decoder = decoder
}
public func decoded<T: Decodable>(_ objectType: T.Type,
with request: RequestObject,
completion: @escaping (GeneralResponse<T>?, Error?) -> Void) {
// Here you should get data from the network call.
// For compilation, we can create an empty object.
let data = Data()
// Now parsing
do {
let response = try self.decoder.decode(GeneralResponse<T>.self, from: data)
completion(response, nil)
} catch {
completion(nil, error)
}
}
}
用法
let request = RequestObject(method: "GET", path: "https://url.com", params: [:])
WebService().decoded([ItemDemoModel].self, with: request) { (response, error) in
if let items = response?.response {
print(items)
}
}
P.S;您必须使用如下声明数组和字典,
let array: Array<SomeType>
let dictionary: Dictionary<String: SomeType>
let arrayOfDictionary: Array<Dictionary<String: SomeType>>
但是使用Swift
的类型推断,你可以像下面这样简单地声明一个array
和一个dictionary
,
let array: [SomeType]
let dictionary: [String: SomeType]
let arrayOfDictionary: [[String: SomeType]]
这里有一个函数,您可能想使用它来解码 JSON:
func decode<T: Decodable>(_ data: Data, completion: @escaping ((T) -> Void)) {
do {
let model = try JSONDecoder().decode(T.self, from: data)
completion(model)
} catch {
log(error.localizedDescription, level: .error)
}
}
所以你可以像这样调用你的函数:
decode(data, completion: { (user: User) in
// Do something with your parsed user struct or whatever you wanna parse
})
希望对您有所帮助 :D
如何将 json 解码为 swift 中的通用模型?
在 java 解码 json 中,我使用 GSON,一般来说,我使用 <T<E>> or ArrayList<E>
并不重要。在 swift 中,数组是一个结构,不能继承,它有未实现可解码。
我正在寻找一个通用的优雅 class 用于我所有的网络服务。
我的场景:
我有 json 回复
{
"status": true,
"message": "",
"code": 200,
"response": [{
"id": 43
}]
}
以及来自 Web 服务的通用响应模型:
class GeneralResponse< T : Decodable >:NSObject,Decodable{
var status = false
var message = ""
var code = -1
var response : T?
private enum CodingKeys: String, CodingKey {
case status
case message
case code
case response
}
required public init(from decoder: Decoder) throws{
let container = try decoder.container(keyedBy: CodingKeys.self)
status = try container.decode(Bool.self, forKey: .status)
message = try container.decode(String.self, forKey: .message)
code = try container.decode(Int.self, forKey: .code)
response = try container.decode(T.self, forKey: .response)
}
}
class ItemDemoModel:Decodable {
var id = -1
private enum ItemDemModelCodingKeys : String, CodingKey {
case id
}
required init(from decoder:Decoder) throws {
let container = try decoder.container(keyedBy: ItemDemModelCodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
}
}
响应变量可以是 ItemDemoModel 或 ItemDemoModel 数组。
例如:
可以是GeneralResponse<Array<ItemDemoModel>>>
或 GeneralResponse<ItemDemoModel>>
谢谢。
Array<T>
符合 Decodable
如果 T
符合 Decodable
,那么 GeneralResponse<[ItemDemoModel]>
不会产生任何错误。
如图所示:
您可以简单地这样做:
let decoder = JSONDecoder()
let obj = try decoder.decode(type, from: json.data(using: .utf8)!)
如果你声明一个 Decodable
属性与 json
中的键同名,那么你真的不需要 enum
来定义 Coding
键和一个使用密钥手动映射每个 属性 的初始化程序。
此外,没有必要从 NSObject
in Swift
继承,除非你有一个特定的用例。查看声明,似乎没有必要,所以您的 GeneralResponse
可以像这样简单地重新声明,
class GeneralResponse<T: Decodable>: Decodable {
var code: Int
var status: Bool
var message: String?
var response : T?
}
同理,ItemDemoModel
可以这样声明,
class ItemDemoModel: Decodable {
var id: Int
}
现在您可以按如下方式设置您的服务以获得任何请求的 GeneralResponse<T>
,
struct RequestObject {
var method: String
var path: String
var params: [String: Any]
}
class WebService {
private let decoder: JSONDecoder
public init(_ decoder: JSONDecoder = JSONDecoder()) {
self.decoder = decoder
}
public func decoded<T: Decodable>(_ objectType: T.Type,
with request: RequestObject,
completion: @escaping (GeneralResponse<T>?, Error?) -> Void) {
// Here you should get data from the network call.
// For compilation, we can create an empty object.
let data = Data()
// Now parsing
do {
let response = try self.decoder.decode(GeneralResponse<T>.self, from: data)
completion(response, nil)
} catch {
completion(nil, error)
}
}
}
用法
let request = RequestObject(method: "GET", path: "https://url.com", params: [:])
WebService().decoded([ItemDemoModel].self, with: request) { (response, error) in
if let items = response?.response {
print(items)
}
}
P.S;您必须使用如下声明数组和字典,
let array: Array<SomeType>
let dictionary: Dictionary<String: SomeType>
let arrayOfDictionary: Array<Dictionary<String: SomeType>>
但是使用Swift
的类型推断,你可以像下面这样简单地声明一个array
和一个dictionary
,
let array: [SomeType]
let dictionary: [String: SomeType]
let arrayOfDictionary: [[String: SomeType]]
这里有一个函数,您可能想使用它来解码 JSON:
func decode<T: Decodable>(_ data: Data, completion: @escaping ((T) -> Void)) {
do {
let model = try JSONDecoder().decode(T.self, from: data)
completion(model)
} catch {
log(error.localizedDescription, level: .error)
}
}
所以你可以像这样调用你的函数:
decode(data, completion: { (user: User) in
// Do something with your parsed user struct or whatever you wanna parse
})
希望对您有所帮助 :D