Swift 4.1可编码/可分解嵌套数组 [英] Swift 4.1 Codable/Decodable Nested Array

查看:177
本文介绍了Swift 4.1可编码/可分解嵌套数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用最新的swift4.1编码器/解码器,需要更复杂的json的帮助:

Need some help with more complicated json, with the newest swift4.1 encoder/decoder:

结构:

struct LMSRequest: Decodable {
let id : Int?
let method : String?
let params : [String]?
enum CodingKeys: String, CodingKey {
    case id = "id"
    case method = "method"
    case params = "params"
}
init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    id = try values.decodeIfPresent(Int.self, forKey: .id)
    method = try values.decodeIfPresent(String.self, forKey: .method)
    params = try values.decodeIfPresent([String].self, forKey: .params)
}}

json:

let json = """
{
  "id": 1,
  "method": "slim.request",
  "params": [
    "b8:27:eb:db:6d:62",
    [
      "serverstatus",
      "-",
      1,
      "tags:GPASIediqtymkovrfijnCYXRTIuwxNlasc"
    ]
  ]
}
""".data(using: .utf8)!

代码:

let decoder = JSONDecoder()
let lms = try decoder.decode(LMSRequest.self, from: json)
print(lms)

预计会解码字符串时出错,但找到了数组.它来自"params"数组中的嵌套数组...真的对如何构建它有所帮助,谢谢!

Error is expected to decode string but found array instead. It's coming from the nested array within the "params" array... really stuck on how to build this out, Thanks!

推荐答案

鉴于您所描述的内容,您应将params存储为这样的枚举:

Given what you've described, you should store params as an enum like this:

enum Param: CustomStringConvertible {
    case string(String)
    case int(Int)
    case array([Param])

    var description: String {
        switch self {
        case let .string(string): return string
        case let .int(int): return "\(int)"
        case let .array(array): return "\(array)"
        }
    }
}

参数可以是字符串,整数或更多参数的数组.

A param can either be a string, an int, or an array of more params.

接下来,您可以依次尝试每个选项,以使参数可解码:

Next, you can make Param Decodable by trying each option in turn:

extension Param: Decodable {
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let string = try? container.decode(String.self) {
            self = .string(string)
        } else if let int = try? container.decode(Int.self) {
            self = .int(int)
        } else {
            self = .array(try container.decode([Param].self))
        }
    }
}

鉴于此,LMSRequest中无需自定义解码逻辑:

Given this, there's no need for custom decoding logic in LMSRequest:

struct LMSRequest: Decodable {
    let id : Int?
    let method : String?
    let params : [Param]?
}

作为旁注,我将仔细考虑这些字段是否都是真正的可选字段. id是可选的非常令人惊讶,method是可选的非常令人惊讶,并且params是可选的也有些令人惊讶.如果它们不是真正可选的,则不要在类型中将它们设置为可选.

As a side note, I would carefully consider whether these fields are all truly optional. It's very surprising that id is optional, and quite surprising that method is optional, and slightly surprising that params are optional. If they're not really optional, don't make them optional in the type.

从您的评论中,您可能会误解如何访问枚举. params[1]不是[Param].这是.array([Param]).因此,您必须对其进行模式匹配,因为它可能是字符串或整数.

From your comments, you're probably misunderstanding how to access enums. params[1] is not a [Param]. It's an .array([Param]). So you have to pattern match it since it might have been a string or an int.

if case let .array(values) = lms.params[1] { print(values[0]) }

也就是说,如果您经常这样做,则可以通过对Param进行扩展来简化此操作:

That said, if you're doing this a lot, you can make this simpler with extensions on Param:

extension Param {
    var stringValue: String? { if case let .string(value) = self { return value } else { return nil } }
    var intValue: Int? { if case let .int(value) = self { return value } else { return nil } }
    var arrayValue: [Param]? { if case let .array(value) = self { return value } else { return nil } }

    subscript(_ index: Int) -> Param? {
        return arrayValue?[index]
    }
}

这样,您可以说出类似的话

With that, you can say things like:

let serverstatus: String? = lms.params[1][0]?.stringValue

可能更接近您的想法. (: String?只是为了明确返回的类型;它不是必需的.)

Which is probably closer to what you had in mind. (The : String? is just to be clear about the returned type; it's not required.)

有关此方法的更复杂且可行的示例,请参见我的通用JSON可解码这是其中的一个子集.

For a more complex and worked-out example of this approach, see my generic JSON Decodable that this is a subset of.

这篇关于Swift 4.1可编码/可分解嵌套数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆