快速将json解码为通用数组或类 [英] decoding a json to generic array or class in swift

查看:138
本文介绍了快速将json解码为通用数组或类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何快速将json解码为通用模型?
在Java中用于解码json的Java中,我使用GSON,一般而言,我都使用<T<E>> or ArrayList<E>没关系.在swift Array中,它是一个结构体,不能继承,并且尚未实现Decodable.

How do you decode json to a generic model in swift?
In java for decoding json I use GSON and in general it does not matter I use <T<E>> or ArrayList<E>.In swift Array is a struct and can't be inheritance and it has not implemented Decodable.

我正在寻找在我的所有Web服务中使用的通用优雅类.

I'm looking for a generic elegant class to use in all my web service.

我的情况:
我有json响应

My scenario:
I have json response

{
"status": true,
"message": "",
"code": 200,
"response": [{
    "id": 43
}]
}

和来自Web服务的通用响应模型如下:

and a generic reponse model like this from web services:

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>>

response variable can be ItemDemoModel or an array of ItemDemoModel.
For example:
It can be GeneralResponse<Array<ItemDemoModel>>> or GeneralResponse<ItemDemoModel>>

谢谢.

推荐答案

如果您声明的Decodable属性与json中的键名称相同,那么您实际上并不需要enum来定义键和一个初始化程序,以使用键手动映射每个属性.

If you declare a Decodable properties with same name as the key in json then you don't really need an enum to define Coding keys and an initializer to manually map every property with the key.

此外,在您有特定的用例之前,也无需从Swift中的NSObject继承.查看该声明,似乎没有必要,因此可以像这样简单地重新声明您的GeneralResponse

Also, there is no need to inherit from NSObject in Swift until you have a specific use case for that. Looking at the declaration, it seems unnecessary so your GeneralResponse can be redeclared as simple as this,

class GeneralResponse<T: Decodable>: Decodable {

    var code: Int
    var status: Bool
    var message: String?
    var response : T?
}

类似地,可以将ItemDemoModel声明为此,

Similarly, ItemDemoModel can be declared as this,

class ItemDemoModel: Decodable {
     var id: Int
}


现在,您可以按照以下步骤设置服务,以获取GeneralResponse<T>任何请求,


Now you can setup your service as below to get the GeneralResponse<T> for any request,

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;您必须习惯于如下声明数组和字典,

P.S; You must be used to declare arrays and dictionaries as below,

let array: Array<SomeType>
let dictionary: Dictionary<String: SomeType>
let arrayOfDictionary: Array<Dictionary<String: SomeType>>

但是通过Swift的类型推断,您可以像下面这样简单地声明arraydictionary

But with Swift's type inference, you can declare an array and a dictionary as simple as below,

let array: [SomeType]
let dictionary: [String: SomeType]
let arrayOfDictionary: [[String: SomeType]]

这篇关于快速将json解码为通用数组或类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆