【问题标题】:Decode json array data with different datatypes in IOS using struct decodable swift 4/5在IOS中使用struct decodable swift 4/5解码不同数据类型的json数组数据
【发布时间】:2019-12-21 05:32:11
【问题描述】:

我尝试使用它来构造结构和解码,但它只有在所有数据类型都与定义的相同时才有效

例如下面的代码可以正常工作

{"key1": "stringValue", "key2": intValue, "key3": ["stringData1", "stringData2", "stringData3"]}
struct User: Decodable               
{
    var key1: String
    var key2: Int
    var key3: [String]
}

let decoder = JSONDecoder()
let decodedJsonData = try decoder.decode(User.self, from: data)
print(decodedJsonData)

如果key3包含不同的数据类型,我应该怎么解码?

{"key1": "stringValue", "key2": intValue, "key3": ["stringData1", IntData, FloatData]}

【问题讨论】:

  • 最好的解决方案是在服务器上进行更改以发送一致的数据。
  • 感谢@vadian 的回复,但实际上在服务器端无法更改,还有其他解决方案吗?
  • 您可以编写一个自定义初始化程序来检查类型或将数组声明为具有关联类型的自定义枚举。在任何情况下,您都必须自定义解码过程。
  • “不同数据类型”的具体种类有哪些。你的意思是它将是一个“字符串或整数或浮点数”的数组?或者该列表中是否还有其他特定数据类型?您在此处给出的示例不是合法的 JSON,这使得回答问题变得困难。您能否提供合法的 JSON 以及您想到的结果结构类型?在 JSON 中,整数和浮点数之间没有区别。它们都只是“数字”。你打算有区别吗?你打算如何区分它们?能举个例子吗?
  • 我想知道为什么标准库中没有通用类型来解组这样的常见任务

标签: ios swift json-deserialization codable decodable


【解决方案1】:

使用带有关联值的枚举:

struct User: Codable {
    let command, updated: Int
    let data: [Datum]
}

enum Datum: Codable {
    case double(Double)
    case string(String)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Double.self) {
            self = .double(x)
            return
        }
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        throw DecodingError.typeMismatch(Datum.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Datum"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .double(let x):
            try container.encode(x)
        case .string(let x):
            try container.encode(x)
        }
    }
}

要获取 data 中的各个值,请使用如下代码:

let json = """
    {"command": 1, "updated": 2, "data": ["stringData1", 42, 43]}
    """.data(using: .utf8)

do {
    let user = try JSONDecoder().decode(User.self, from: json!)

    for d in user.data {
        switch d {
        case .string(let str): print("String value: \(str)")
        case .double(let dbl): print("Double value: \(dbl)")
        }
    }
} catch {
    print(error)
}

【讨论】:

  • 谢谢@gereon,此代码可以处理字符串和双精度的组合,但输出类似于 string("pavan") double("5.5505") 我无法转换它也用这个写一个条件,你能帮我解决这个问题吗
  • 更新了我的答案。在此处查找有关关联值的更多信息:docs.swift.org/swift-book/LanguageGuide/Enumerations.html#ID148
  • @PavanKumar 如果您不想一直进行模式匹配,还可以将 var stringValue: String? { ... } 等实用函数添加到 Datum
猜你喜欢
  • 2018-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-24
  • 2018-09-07
  • 1970-01-01
  • 2018-03-30
  • 2018-10-21
相关资源
最近更新 更多