Pass A Generic Codable Type as Parameter to a Method for Saving to Realm

ⅰ亾dé卋堺 提交于 2019-12-11 17:04:53

问题


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:


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


来源:https://stackoverflow.com/questions/53162319/pass-a-generic-codable-type-as-parameter-to-a-method-for-saving-to-realm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!