我正在尝试从具有通用嵌套对象的json对象解码,为此,我想在解码时动态传递类的类型。
例如,我的课堂是EContactModel和ENotificationModel,它们扩展了ObjectModel(和:Codable)。 ENotificationModel可以包含嵌套的ObjectModel(可以是联系人,通知或其他对象模型)。
我有一个这样的字典:
static let OBJECT_STRING_CLASS_MAP = [
"EContactModel" : EContactModel.self,
"ENotificationModel" : ENotificationModel.self
...
]
我在ENotificationModel中的解码init方法如下:
required init(from decoder: Decoder) throws
{
try super.init(from: decoder)
let values = try decoder.container(keyedBy: CodingKeys.self)
...
//decode some fields here
self.message = try values.decodeIfPresent(String.self, forKey: .message)
...
//decode field "masterObject" of generic type ObjectModel
let cls = ObjectModelTypes.OBJECT_STRING_CLASS_MAP[classNameString]!
let t = type(of: cls)
print(cls) //this prints "EContactModel"
self.masterObject = try values.decodeIfPresent(cls, forKey: .masterObject)
print(t) //prints ObjectModel.Type
print(type(of: self.masterObject!)) //prints ObjectModel
}
我也尝试传递type(of:anObjectInstanceFromADictionary),但仍然无法正常工作,但是如果我传递type(of:EContactModel()),它就可以工作。我无法理解这一点,因为两个对象是相同的(即EContactModel的实例)
有解决方案吗?
答案 0 :(得分:1)
您可以使用可选变量声明对象模型,然后让JSONDecoder为您解决。
class ApiModelImage: Decodable {
let file: String
let thumbnail_file: String
...
}
class ApiModelVideo: Decodable {
let thumbnail: URL
let duration: String?
let youtube_id: String
let youtube_url: URL
...
}
class ApiModelMessage: Decodable {
let title: String
let body: String
let image: ApiModelImage?
let video: ApiModelVideo?
...
}
然后您要做的就是....
if let message = try? JSONDecoder().decode(ApiModelMessage.self, from: data) {
if let image = message.image {
print("yay, my message contains an image!")
}
if let video = message.video {
print("yay, my message contains a video!")
}
}
或者,您可以在调用API代码时使用泛型并指定类型:
func get<T: Decodable>(from endpoint: String, onError: @escaping(_: Error?) -> Void, onSuccess: @escaping (_: T) -> Void) {
getData(from: endpoint, onError: onError) { (data) in
do {
let response = try JSONDecoder().decode(T.self, from: data)
onSuccess(response)
} catch {
onError(error)
}
}
}
通过这种方式,您只需要确保定义了预期的响应类型即可:
let successCb = { (_ response: GetUnreadCountsResponse) in
...
}
ApiRequest().get(from: endpoint, onError: { (_) in
...
}, onSuccess: successCb)
由于您将SuccessCb定义为需要GetUnreadCountsResponse模型,因此API get方法泛型将在运行时为GetUnreadCountsResponse类型。
祝你好运!