Decoding a JSON without keys in Swift 4

前端 未结 3 1314
别跟我提以往
别跟我提以往 2021-02-01 05:49

I\'m using an API that returns this pretty horrible JSON:

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


        
相关标签:
3条回答
  • 2021-02-01 06:03

    This is a bit interesting for decoding.

    You don't have any key. So it eliminates the need of a wrapper struct.

    But look at the inner types. You get mixture of String and [String] types. So you need something that deals with this mixture type. You would need an enum to be precise.

    // 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)
            }
        }
    }
    

    Decoding Process:

    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)
    }
    
    0 讨论(0)
  • 2021-02-01 06:04

    If the structure stays the same, you can use this Decodable approach.

    First create a decodable Model like this:

    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)
        }
    }
    

    Or if you really want to keep the JSON's structure, like this:

    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]
        }
    }
    

    And use it like this

    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)
    }
    
    0 讨论(0)
  • 2021-02-01 06:22

    A possible solution is to use the JSONSerialization, then you might simply dig inside such json, doing so:

    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
                }
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题