Try to parse JSON Array of Arrays on Swift

Viewed 171

Here is the json code:

{
  
    "rows":
        [[{
            "text":"some text",
            "type":{
                "type":"inlineUrl",
                "url":"https://nothing.com"
            }
        }],
        [{
            "text":"some text",
            "type":{
                "type":"inlineCallback",
                "data":"some data"
            }
        },
        {
            "text":"some text",
            "type":{
                "type":"inlineCallback",
                "data":"some data"
            }
        }
        ]]
        
}

A more abbreviated would look like: Rows = [ [Row1], [Row2, Row3] ]

And I'm trying to get it to work like this:

struct ReplyHandler: Codable {
    let rows: [RowsHandler]

    enum CodingKeys: String, CodingKey {
        case rows
    }
}

struct RowsHandler: Codable {
    let row1: [RowHandler]
    let row2: [Row2Handler]
    
    enum CodingKeys: String, CodingKey {
        case row1
        case row2
    }
}

struct RowHandler: Codable {
    let text: String
    let type: TypeHandler
    
    enum CodingKeys: String, CodingKey {
        case type = "type"
        case text = "text"
    }
}

struct Row2Handler: Codable {
    let row1: RowHandler
    let row2: RowHandler

    enum CodingKeys: String, CodingKey {
        case row1
        case row2
    }
}

struct TypeHandler: Codable {
    let type: String
    let url: String

    enum CodingKeys: String, CodingKey {
        case type = "type"
        case url = "url"
    }
    
}

But Xcode compiler gives this error:

Expected to decode String but found an array instead.

Don't understand how to properly nest other arrays in the array

While posting my question, I noticed that the arrays in "type" are different: the first row have url, the second and third have data, but anyway, it's not a point.

2 Answers

You can simplify your model to something like this:

struct ReplyHandler: Codable {
    let rows: [[RowHandler]]
}

struct RowHandler: Codable {
    let text: String
    let type: TypeHandler
}

struct TypeHandler: Codable {
    let type: String
    var url: String?
    var data: String?
}

Notice that url and data properties in TypeHandler are optionals to cover both cases.

Although manual JSON parsing is useful I think that it must be much easier to use tool like this https://app.quicktype.io/ to convert JSON into Swift classes or structs

For you JSON it provides this result

// MARK: - Welcome
struct Welcome: Codable {
    let rows: [[Row]]
}

// MARK: - Row
struct Row: Codable {
    let text: String
    let type: TypeClass
}

// MARK: - TypeClass
struct TypeClass: Codable {
    let type: String
    let url: String?
    let data: String?
}
Related