json - Swift - JSONDecoder - 解码通用嵌套类
问题描述
我对 Swift 很陌生,我正在尝试创建一个类树来为我的数据建模。我想使用 JSONEncoder 和 JSONDecoder 来发送和接收对象。我在解码另一个对象(嵌套)中的泛型类时遇到问题,因为在 init(from: decoder) 方法中,我无法访问可以帮助我的其他属性。
在我的代码中:
NestedSecondObject 扩展了 NestedObjects,后者扩展了 Codable - NestedObject 可以通过 NesteThirtObject 等进行扩展...
Contact 扩展了 Object1,后者扩展了 Codable;Contact 包含一个 NestedObject 类型(可以是运行时 NestedObject 的任何子类)
因为 JSONEncoder 和 JSONDecoder 默认不支持继承,所以我重写了方法“encode”和 init(from: decoder),如下所述:Using Decodable in Swift 4 with Inheritance
我的代码是:
class NestedSecondObject: NestedObject {
var subfield2: Int?
private enum CodingKeys : String, CodingKey {
case subfield2
}
override init() { super.init() }
override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(subfield2, forKey: .subfield2)
}
required init(from decoder: Decoder) throws
{
try super.init(from: decoder)
let values = try decoder.container(keyedBy: CodingKeys.self)
self.subfield2 = try values.decode(Int.self, forKey: .subfield2)
}
}
class Contact:Object1 {
var name: String = ""
var age: Int = 0
var address: String = ""
// var className = "biz.ebas.platform.generic.shared.EContactModel"
var nestedObject:NestedObject?
private enum CodingKeys : String, CodingKey {
case name,age,address,nestedObject
}
override init() { super.init() }
override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(age, forKey: .age)
try container.encode(address, forKey: .address)
try container.encode(nestedObject, forKey: .nestedObject)
}
required init(from decoder: Decoder) throws
{
try super.init(from: decoder)
print(type(of: self))
print(type(of: decoder))
let values = try decoder.container(keyedBy: CodingKeys.self)
print(type(of: values))
self.name = try values.decode(String.self, forKey: .name)
self.age = try values.decode(Int.self, forKey: .age)
self.address = try values.decode(String.self, forKey: .address)
self.nestedObject = try values.decodeIfPresent(???.self, forKey: .nestedObject) // HERE i need to know what ???.self is
}
}
解码是:
let jsonDec = JSONDecoder()
let jsonData = json?.data(using: .utf8)
let decodedContact: Contact = try jsonDec.decode(Contact.self, from: jsonData!)
所以,基本上,当我向服务器发出请求时,我知道我收到了什么类型(假设我请求 NestedSecondObject),但是我如何将它传递给方法“init(来自解码器:解码器)”?
我尝试扩展 JSONDecoder 类并添加一个简单的属性,如下所示:
class EJSONDecoder: JSONDecoder {
var classType:AnyObject.Type?
}
但是在所需的init(来自解码器:解码器)方法中,解码器的类型不是EJSONDecoder,是_JSONDecoder,所以我无法访问decoder.classType属性。
任何人都可以提供解决方案或某种解决方法吗?谢谢!
解决方案
新答案
你可以给解码器一个userInfo
数组,你可以在其中存储你想要在解码过程中使用的东西。
let decoder = JSONDecoder()
decoder.userInfo = [.type: type(of: NestedSecondObject.self)]
let decodedContact: Contact = try! decoder.decode(Contact.self, from: json)
extension CodingUserInfoKey {
static let type = CodingUserInfoKey(rawValue: "Type")!
}
然后在解码时使用它:
switch decoder.userInfo[.type]! {
case let second as NestedSecondObject.Type:
self.nestedObject = try values.decode(second, forKey: .nestedObject)
case let first as NestedObject.Type:
self.nestedObject = try values.decode(first, forKey: .nestedObject)
default:
fatalError("didnt work")
}
遗憾的是,我还没有找到跳过开关的方法。
老答案:
解码为
NestedSecondObject.self
如果在 catch 内解码失败
NestedObject.self
. 如果它甚至无法解码为基本类型,请不要捕获您想要失败的 NestedObject 解码原因。
推荐阅读
- date - 为什么 Adaptive Card Input.Date 从所选日期中减去 1 天?
- google-apps-script - 如果行颜色从紫色更改为白色默认颜色然后写
- c++ - 如何将我的 Win32 OpenGL 程序转换为 Mac 兼容版本?
- html - 新手:将旧的 IE html 更新为现代标准
- html - 如何使活动类在 Angular 中工作?
- sql - 查找列值接近当前行之一的行
- python - 向变量添加坐标
- javascript - 我正在尝试从另一个类中调用一个类中的 Javascriptcript 方法,但出现错误
- microsoft-graph-api - 为什么我从 Microsoft Graph 消息订阅中收到空的 Retry-After 标头?
- console - 如何解决 Ipython 深色背景中符号数学的漂亮打印的显示问题?