Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 4从自定义JSON对象解码到不同模型_Json_Swift - Fatal编程技术网

Swift 4从自定义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 } 我有一个类的列表(它们可能包含一些

我有一个websocket,它可以生成不同的json对象。对象不能包含任何公共字段

{
    "type": "apple",
    "kind": "fruit",
    "eatable": true
}
{
    "item": "key",
    "active": true 
}
{
    "tool": "screwdriver",
    "original": "toolBox",
    "cross-head": true
}
我有一个类的列表(它们可能包含一些逻辑),所以我需要解析它来映射一些具有层次结构的模型,例如。 尝试解析失败的结果尝试解析失败的键尝试解析工具箱。有时我需要添加一些新类来解析一些对象,并向现有类添加一些新字段
如何组织分拣类进行解析?

更新

  • 我无法控制后端数据,因此无法向JSON添加任何字段
  • 对象一次一个。我为他们中的大多数人提供了单独的班级模型。问题是选择正确的类来映射JSON字段
    尝试查找您正在查找的模型类的键,如果该键不在该对象中,请尝试其他模型类。这将使您确定哪个模型类适合给定对象

    使用任何其他车型类别中不存在的唯一键

    例如:

    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
    的方式。即使没有泄漏,这也是真的……无论如何,感谢您的提醒。