首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用JSONDecoder解码未知类型的JSON?

如何使用JSONDecoder解码未知类型的JSON?
EN

Stack Overflow用户
提问于 2018-10-20 00:46:56
回答 1查看 2.5K关注 0票数 2

这是我的场景:我有一个swift WebSocket服务器和一个Javascript客户端。通过这个相同的WebSocket,我将发送对应于不同Codable types的各种对象。如果知道正确的类型,那么解码就足够简单了。对我来说,困难的是识别从客户端发送的是哪种类型。我的第一个想法是使用如下所示的JSON:

代码语言:javascript
复制
{type: "GeoMarker", 
 data: {id: "2",
        latitude: "-97.32432"
        longitude: "14.35436"}
}

通过这种方式,我知道如何使用let marker = try decoder.decode(GeoMarker.self)解码data这看起来很简单,但由于某些原因,我就是想不出如何将data对象提取为JSON,以便可以使用GeoMarker类型解码它。

我想出的另一个解决方案是创建一个中间类型,如下所示:

代码语言:javascript
复制
struct Communication: Decodable {
let message: String?
let markers: [GeoMarker]?
let layers: [GeoLayer]?
}

这样,我就可以用以下格式发送JSON:

代码语言:javascript
复制
{message: "This is a message",
 markers: [{id: "2",
           latitude: "-97.32432"
           longitude: "14.35436"},
           {id: "3",
           latitude: "-67.32432"
           longitude: "71.35436"}]
}

并使用let com = try decoder.decode(Communication.self)并展开可选的message、markers和layers变量。这是可行的,但是看起来很笨拙,特别是当我需要更多类型的时候。我可能最终需要8-10后,所有的说和做。

我已经想过了,但我觉得我没有想出一个令人满意的解决方案。会有更好的方法吗?对于我不知道的这类事情有什么标准吗?

编辑--

作为一个自然的后续,在上述相同的情况下,您将如何编码为相同的JSON格式?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-10-20 01:26:04

作为您的首选,您可以通过自定义解码来实现它。

首先,为所有可能的数据类型创建一个具有关联值的枚举。

代码语言:javascript
复制
struct GeoMarker: Decodable {
    let id:Int
    let latitude:Double
    let longitude:Double
}

enum ResponseData {
    case geoMarker(GeoMarker)
    case none
}

现在为您的枚举提供自定义解码,以解析所有不同类型的数据对象。

代码语言:javascript
复制
extension ResponseData: Decodable{
    enum CodingKeys: String, CodingKey {
        case type = "type"
        case data = "data"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let type = try container.decode(String.self, forKey: .type)

        switch type {
        case "GeoMarker":
            let data = try container.decode(GeoMarker.self, forKey: .data)
            self = .geoMarker(data)
        default:
            self = .none
        }
    }
}

你可以像这样使用它...

代码语言:javascript
复制
let json = """
{
    "type": "GeoMarker",
    "data": {
        "id": 2,
        "latitude": -97.32432,
        "longitude": 14.35436
    }
}
"""

let testRes = try? JSONDecoder().decode(ResponseData.self, from: json.data(using: .utf8)!)

if let testRes = testRes {
    if case let ResponseData.geoMarker(geoMarker) = testRes {
        print("\(geoMarker.id) \(geoMarker.latitude)  \(geoMarker.longitude)")
    }
}

要实现自定义编码器,请使用以下代码。

代码语言:javascript
复制
extension ResponseData: Encodable{

func encode(to encoder: Encoder) throws {

    let container = encoder.container(keyedBy: CodingKeys.self)

    if case let .geoMarker(geoMarker) = self {
         try container.encode("Marker", forKey: .type)
         try container.encode(geoMarker, forKey: .data)
    }
}

你可以这样使用它:

代码语言:javascript
复制
let marker = GeoMarker(id:2, latitude: "-97.32432", longitude: "14.35436")
let encoder = JSONEncoder()
let data = try encoder.encode(.geoMarker(marker))
//Send data over WebSocket
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52896731

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档