Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.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:我如何解码json对象数组,而不创建一个包含所述对象数组的结构?_Json_Swift_Jsondecoder_Json Flattener - Fatal编程技术网

swift:我如何解码json对象数组,而不创建一个包含所述对象数组的结构?

swift:我如何解码json对象数组,而不创建一个包含所述对象数组的结构?,json,swift,jsondecoder,json-flattener,Json,Swift,Jsondecoder,Json Flattener,我的数据如下所示: "places": [ { "id": 15, "name": "København", "typeId": 6, "coordinates": { "lat": "55.6760968

我的数据如下所示:

"places": [
        {
            "id": 15,
            "name": "København",
            "typeId": 6,
            "coordinates": {
                "lat": "55.6760968",
                "lng": "12.5683372"
            },
            "count": 2779
        },
        {
            "id": 19,
            "name": "København S",
            "typeId": 3,
            "coordinates": {
                "lat": "55.6508754",
                "lng": "12.5991891"
            },
            "count": 1168
        }
]
我希望避免这种情况:

struct Places: Decodable {
    let places: [Place]
}
这是QuickType.io建议的: 而是在“地点”列表中解码。这样做可以:

let places = try JSONDecoder().decode([Place].self, from: data)
到目前为止,我已经找到了可能的解决方案:

  • “磨损”解决方案:

  • 创建通用可解码数组结构:


  • 如果您发现自己多次需要此功能,那么您可以构建自己的通用结构,该结构可以对找到的任何键进行解码:

    struct Nester<T: Decodable>: Decodable {
        let elements: [T]
        
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            if let key = container.allKeys.first {
                elements = try container.decode([T].self, forKey: key)
            } else {
                // we run into an empty dictionary, let's signal this
                throw DecodingError.typeMismatch([String:Any].self, DecodingError.Context(codingPath: [], debugDescription: "Expected to find at least one key"))
            }
        }
        
        // A coding key that accepts whatever string value it is given
        struct CodingKeys: CodingKey {
            let stringValue: String
            var intValue: Int? { nil }
            
            init?(stringValue: String) {
                self.stringValue = stringValue
            }
                    
            init?(intValue: Int) { return nil }
        }
    }
    
    然后,只需调用新的重载:


    let places=try JSONDecoder().decode(嵌套:[Place].self,from:data)
    

    另外,如果需要,可以在扩展中隐藏复杂结构,结果如下:

    "places": [
            {
                "id": 15,
                "name": "København",
                "typeId": 6,
                "coordinates": {
                    "lat": "55.6760968",
                    "lng": "12.5683372"
                },
                "count": 2779
            },
            {
                "id": 19,
                "name": "København S",
                "typeId": 3,
                "coordinates": {
                    "lat": "55.6508754",
                    "lng": "12.5991891"
                },
                "count": 1168
            }
    ]
    
    扩展JSONDecoder{ func decode(嵌套:[T]。类型,来自数据:data)抛出->[T]{ 尝试解码(Nester.self,from:data).elements } 私有结构嵌套器:可解码{ let元素:[T] init(来自解码器:解码器)抛出{ let container=try decoder.container(keyedBy:CodingKeys.self) 如果let key=container.allkey.first{ elements=try container.decode([T].self,forKey:key) }否则{ 抛出DecodingError.typeMismatch([String:Any].self,DecodingError.Context(编码路径:[],调试说明:“应至少找到一个键”)) } } 结构编码键:编码键{ 让stringValue:String var intValue:Int?{nil} 初始化?(stringValue:String){ self.stringValue=stringValue } init?(intValue:Int){return nil} } } }
    缺点是,如果要扩展JSON以外的其他解码器,则无法重用该结构。

    有一种可能的方法可以避免顶级结构(
    Places
    ),方法是将JSON解码为
    [String:[Place]]
    类型,然后获取字典
    value
    属性的第一个元素:

    let decoder = JSONDecoder()
    do {
        let places = try decoder.decode([String: [Place]].self, from: data)
        print(places.values.first ?? [])
    } catch {
        print(error)
    }
    

    不,你不能。可以说,你需要从头开始。但是为什么这是一个问题,你可以很容易地访问并只保留Place数组?@JoakimDanielson我只是觉得有一个结构很难看,只是为了正确地解码我的json。我担心情况就是这样。
    让places=try JSONDecoder().decode(places.self,from:data)。places
    我开始使用Cristik的答案,但是当我继续为API实现webRepo的其余部分时,我发现上面提到的情况是一个边缘情况,除了一个struct/API调用之外,不适用于任何东西。因此,我最终使用了gcharita提到的方法,它将我的对象解码为[String:[object]]总体而言,我认为Cristik的方法更优雅,如果我需要的话,我会使用它的解决方案。因为我的想法是使用一个不太混乱的名称空间,所以我选择了gcharita的.Cleanear而不是我的解决方案,这增加了新结构的开销:拇指支持:关于
    JSONDecoder
    扩展的想法有利于重用。将这两个答案结合起来会得到一个有趣的结果:)