Decoding a JSON without keys in Swift 4 Decoding a JSON without keys in Swift 4 arrays arrays

Decoding a JSON without keys in Swift 4


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


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


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

import Foundationlet 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            }        }    }}