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