Pass A Generic Codable Type as Parameter to a Meth

2019-08-30 04:36发布

I am trying to create a generic method for decoding some JSON data. I need to cast the JSON data into Objects for later saving in Realm.

For example: Getting the makes, models, colors, and body types of vehicles.

In each of my JSON calls to the results are formatted exactly the same (See my structs at the end of the question). For brevity, I am only showing you Makes and Models, but Colors and Body Types are exactly the same, just with the name changes.

I currently have four methods that I call where Makes.self is replaced with one of the other structs.

if let results = try? JSONDecoder().decode(Makes.self, from: jsonData)) {
        DispatchQueue.main.async {
        //save data to realm
        self?.save(objects: results.data )
    }
}

Once I get my JSON Data, I would like to send my data to a generic method for processing.

So I could call something like :

process(jsonData, modelType: Makes.self)
process(jsonData, modelType: Models.self)
process(jsonData, modelType: Colors.self)
process(jsonData, modelType: Bodies.self)

I have tried variations on generic types but I can't seem to get it right.

func process<T:Codable>(_ jsonData: Data, modelType: T.Type = T.self) {

        if let results = try? JSONDecoder().decode(modelType.self, from: jsonData) {
            DispatchQueue.main.async {
                //save data to realm
                self?.save(objects:results.data)
            }
        }
}

How can I pass a Decodable Protocol type as a generic?

MAKES

import RealmSwift

struct Makes: Codable {
    let result: String
    let data: [Make]

    enum CodingKeys: String, CodingKey {
        case result = "Result"
        case data = "Data"
    }
}

class Make: Object, Codable {
    @objc dynamic var key: String
    @objc dynamic var value: String
    @objc dynamic var shortCode: String
    @objc dynamic var active: Bool

    enum CodingKeys: String, CodingKey {
        case key = "Key"
        case value = "Value"
        case shortCode = "ShortCode"
        case active = "Active"
    }
}

MODELS

import RealmSwift

struct Makes: Codable {
    let result: String
    let data: [Make]

    enum CodingKeys: String, CodingKey {
        case result = "Result"
        case data = "Data"
    }
}

class Make: Object, Codable {
    @objc dynamic var key: String
    @objc dynamic var value: String
    @objc dynamic var shortCode: String
    @objc dynamic var active: Bool

    enum CodingKeys: String, CodingKey {
        case key = "Key"
        case value = "Value"
        case shortCode = "ShortCode"
        case active = "Active"
    }
}

1条回答
【Aperson】
2楼-- · 2019-08-30 04:58

Why would you expect any Codable type to have a data property? results.data cannot work... You need to make T a subclass of Object to be able to save it to Realm and also Decodable to be able to pass it to the decode method.

func process<T:Object>(_ jsonData: Data, modelType: T.Type) where T:Decodable {
    if let results = try? JSONDecoder().decode(modelType.self, from: jsonData) {
        DispatchQueue.main.async {
            //save data to realm
            self?.save(objects:results)
        }
    }
}
查看更多
登录 后发表回答