【问题标题】:Decoding a JSON without keys in Swift 4在 Swift 4 中解码没有键的 JSON
【发布时间】:2018-08-15 07:02:10
【问题描述】:

我正在使用一个返回这个非常可怕的 JSON 的 API:

[
  "A string",
  [
    "A string",
    "A string",
    "A string",
    "A string",
    …
  ]
]

我正在尝试使用 JSONDecoder 解码嵌套数组,但它没有单个键,我真的不知道从哪里开始......你有什么想法吗?

非常感谢!

【问题讨论】:

    标签: arrays json swift swift4 jsondecoder


    【解决方案1】:

    这个解码有点意思。

    您没有任何key。所以它消除了对包装器 struct 的需要。

    但是看看内部类型。你得到String[String] 类型的混合。所以你需要一些处理这种混合物类型的东西。准确地说,您需要enum

    // I've provided the Encodable & Decodable both with Codable for clarity. You obviously can omit the implementation for Encodable
    enum StringOrArrayType: Codable {
        case string(String)
        case array([String])
    
        init(from decoder: Decoder) throws {
            let container = try decoder.singleValueContainer()
            do {
                self = try .string(container.decode(String.self))
            } catch DecodingError.typeMismatch {
                do {
                    self = try .array(container.decode([String].self))
                } catch DecodingError.typeMismatch {
                    throw DecodingError.typeMismatch(StringOrArrayType.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Encoded payload conflicts with expected type"))
                }
            }
        }
    
        func encode(to encoder: Encoder) throws {
            var container = encoder.singleValueContainer()
            switch self {
            case .string(let string):
                try container.encode(string)
            case .array(let array):
                try container.encode(array)
            }
        }
    }
    

    解码过程:

    let json = """
    [
      "A string",
      [
        "A string",
        "A string",
        "A string",
        "A string"
      ]
    ]
    """.data(using: .utf8)!
    
    do {
        let response = try JSONDecoder().decode([StringOrArrayType].self, from: json)
        // Here, you have your Array
        print(response) // ["A string", ["A string", "A string", "A string", "A string"]]
    
        // If you want to get elements from this Array, you might do something like below
        response.forEach({ (element) in
            if case .string(let string) = element {
                print(string) // "A string"
            }
            if case .array(let array) = element {
                print(array) // ["A string", "A string", "A string", "A string"]
            }
        })
    } catch {
        print(error)
    }
    

    【讨论】:

      【解决方案2】:

      如果结构保持不变,您可以使用这种Decodable 方法。

      首先像这样创建一个可解码的模型:

      struct MyModel: Decodable {
          let firstString: String
          let stringArray: [String]
      
          init(from decoder: Decoder) throws {
              var container = try decoder.unkeyedContainer()
              firstString = try container.decode(String.self)
              stringArray = try container.decode([String].self)
          }
      }
      

      或者如果你真的想保留 JSON 的结构,像这样:

      struct MyModel: Decodable {
          let array: [Any]
      
          init(from decoder: Decoder) throws {
              var container = try decoder.unkeyedContainer()
              let firstString = try container.decode(String.self)
              let stringArray = try container.decode([String].self)
              array = [firstString, stringArray]
          }
      }
      

      并像这样使用它

      let jsonString = """
      ["A string1", ["A string2", "A string3", "A string4", "A string5"]]
      """
      if let jsonData = jsonString.data(using: .utf8) {
          let myModel = try? JSONDecoder().decode(MyModel.self, from: jsonData)
      }
      

      【讨论】:

        【解决方案3】:

        一个可能的解决方案是使用JSONSerialization,然后你可以简单地挖掘这样的json,这样做:

        import Foundation
        
        let jsonString = "[\"A string\",[\"A string\",\"A string\", \"A string\", \"A string\"]]"
        if let jsonData = jsonString.data(using: .utf8) {
            if let jsonArray = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [Any] {
                jsonArray.forEach {
                    if let innerArray = $0 as? [Any] {
                        print(innerArray) // this is the stuff you need
                    }
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2019-08-05
          • 2021-10-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多