Swift 4从自定义JSON对象解码到不同模型
我有一个websocket,它可以生成不同的json对象。对象不能包含任何公共字段Swift 4从自定义JSON对象解码到不同模型,json,swift,Json,Swift,我有一个websocket,它可以生成不同的json对象。对象不能包含任何公共字段 { "type": "apple", "kind": "fruit", "eatable": true } { "item": "key", "active": true } { "tool": "screwdriver", "original": "toolBox", "cross-head": true } 我有一个类的列表(它们可能包含一些
{
"type": "apple",
"kind": "fruit",
"eatable": true
}
{
"item": "key",
"active": true
}
{
"tool": "screwdriver",
"original": "toolBox",
"cross-head": true
}
我有一个类的列表(它们可能包含一些逻辑),所以我需要解析它来映射一些具有层次结构的模型,例如。
尝试解析失败的结果尝试解析失败的键尝试解析工具箱。有时我需要添加一些新类来解析一些对象,并向现有类添加一些新字段如何组织分拣类进行解析?
更新
尝试查找您正在查找的模型类的键,如果该键不在该对象中,请尝试其他模型类。这将使您确定哪个模型类适合给定对象 使用任何其他车型类别中不存在的唯一键 例如:
var array = NSArray(array: [[
"type": "apple",
"kind": "fruit",
"eatable": true
],
[
"item": "key",
"active": true
],
[
"tool": "screwdriver",
"original": "toolBox",
"cross-head": true
]])
for model in array as! [NSDictionary]
{
if(model.value(forKey: "type") != nil)
{
print("use Fruit Model Class")
}
else if(model.value(forKey: "item") != nil)
{
print("use second model class")
}
else
{
print("use third model class")
}
}
您可以这样做: 首先,您声明您的类型符合
可解码
协议:
struct Fruit : Decodable {
let type : String
let kind : String
let eatable : Bool
}
struct Tool : Decodable {
let tool : String
let original : String
let crossHead : Bool
enum CodingKeys: String, CodingKey {
case tool = "tool"
case original = "original"
case crossHead = "cross-head"
}
}
然后扩展Decodable
“反向”使用泛型:
extension Decodable {
static func decode(data : Data, decoder : JSONDecoder = JSONDecoder()) -> Self? {
return try? decoder.decode(Self.self, from: data)
}
}
然后扩展JSONDecoder
,在要测试的类型中尝试可解码类型:
extension JSONDecoder {
func decode(possibleTypes : [Decodable.Type], from data: Data) -> Any? {
for type in possibleTypes {
if let value = type.decode(data: data, decoder: self) {
return value
}
}
return nil
}
}
最终指定要尝试和解码的类型:
let decodableTypes : [Decodable.Type] = [Fruit.self, Tool.self]
然后,您可以使用它来解码JSON:
let jsonString = """
{
"tool": "screwdriver",
"original": "toolBox",
"cross-head": true
}
"""
let jsonData = jsonString.data(using: .utf8)!
let myUnknownObject = JSONDecoder().decode(possibleTypes: decodableTypes, from: jsonData)
瞧
现在,您可以在decodableTypes
中添加任意数量的类型,只要它们符合Decodable
协议
这不是最好的方法,因为如果你有很多类型,它不是最优的,但是这样你就不需要在数据中添加一个区分字段。
如果所有这些字段都是相关的或联合的样式,你可以考虑用户EnUM,这也是很容易实现的。p> let data1 = """
[{
"type": "apple",
"kind": "fruit",
"eatable": true
},
{
"item": "key",
"active": true
},
{
"tool": "screwdriver",
"original": "toolBox",
"cross-head": true
}]
""".data(using: .utf8)!
struct JSONType : Decodable{
let type: String
let kind: String
let eatable : Bool
}
struct JSONItem : Decodable{
let item: String
let active : Bool
}
struct JSONTool : Decodable{
let tool: String
let original : String
let crosshead : Bool
enum CodingKeys: String, CodingKey {
case tool = "tool"
case original = "original"
case crosshead = "cross-head"
}
}
enum JSONData : Decodable{
case type(JSONType)
case item(JSONItem)
case tool(JSONTool)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do{ let temp = try container.decode(JSONType.self); self = .type(temp) ; return}
catch{do { let temp = try container.decode(JSONItem.self) ; self = .item(temp) ; return}
catch{ let temp = try container.decode(JSONTool.self) ; self = .tool(temp) ; return}}
try self.init(from: decoder)
}
func getValue()-> Any{
switch self {
case let .type(x): return x
case let .item(x): return x
case let .tool(x): return x
}
}
}
let result = try JSONDecoder().decode([JSONData].self, from: data1)
print(result[0].getValue())
print (result[1].getValue())
print (result[2].getValue())
很难理解你在问什么以及你的应用程序中发生了什么。您是一次接收一个对象,还是一个数组或某种树结构中的对象,您需要添加一些类或字段是什么意思,这与您的问题有什么关系?所有这些对象都是单个响应,即一个JSON响应对象?那么您是单独请求这些对象吗?因为在这种情况下,您事先知道响应是什么,因此需要解码什么类/结构。不,我不请求它们通过WebSocket来的任何对象。这就是为什么我不知道我得到了什么数据。这是一个很好的决定,但我想有一些更自动的方法来决定使用哪个模型。有时我需要向我的项目中添加一个新类,所以我必须在这里添加一些规则。完美的做法是在类本身内部有一些规则。向每个类添加静态函数,以检查给定对象是否包含该模型类所需的唯一键。这将使您更容易访问和使用itI。我认为这是确定给定对象的模型所能做的最好的方法。我想是的。。。不幸的是,不要在Swift中使用
NSArray/NSDictionary
和值(forKey
。您正在与强类型系统作斗争。谢谢,这就是我所寻找的。可解码的静态扩展。解码器:jsondeconder=jsondeconder()
-不要这样做,JSONDecoder
当前正在泄漏内存,如果每次调用扩展方法时都要创建新实例,那么会有大量泄漏内存,最好为参数默认值创建一些静态全局实例。这只是为了使示例简单,目的是使用JSONDecoder代码>在任何情况下。此代码当然不打算以这种方式使用。但我使用此快捷方式清楚地回答了问题,并且没有描述生产代码中必须使用jsondeconder
的方式。即使没有泄漏,这也是真的……无论如何,感谢您的提醒。