Home > Enterprise >  Decode multidimensional unkeyed Json String in Swift
Decode multidimensional unkeyed Json String in Swift

Time:03-30

I try to decode a Json String like this:

[
  [11,0,"text 1"],
  [337,0,"text 2"],
  [63,0,"text 3"]
  ...
]

this is my code to decode:

var stringData: StringData? = nil


                do {
                  let shared = sharedDefaults?.string(forKey: "jsonString")

                    let decoder = JSONDecoder()
                    print("xcode: ")
                    stringData = try decoder.decode(StringData.self, from: shared!.data(using: .utf8)!)
                    
                } catch {
                  print(error)
                }

I think I have a wrong structure to decode multidimensional unkeyed array:

struct StringData: Decodable {
    //let array: [[String]]
    var array: [ArrayData]
    
    init(from decoder: Decoder) throws {
            var container = try decoder.unkeyedContainer()
            //let firstString = try container.decode([String].self)
            array = try container.decode([ArrayData].self)
            //array = [firstString, stringArray]
        }
    
    struct ArrayData: Decodable {
        let id: Int
        let cat: Int
        let text: String
        
        init(from decoder: Decoder) throws {
                var container = try decoder.unkeyedContainer()
               id = try container.decode(Int.self)
                cat = try container.decode(Int.self)
                text = try container.decode(String.self)
            }
        
    }

But I get the error:

debugDescription: "Expected to decode Array<Any> but found a number instead."

What I'm doing wrong?

CodePudding user response:

You're surprisingly close. Your ArrayData is exactly right. It's not clear why you added StringData; it's not needed. The entire solution is:

let result = try JSONDecoder().decode([ArrayData].self, from: json)

If you do want StringData for some reason, this is what it would look like:

struct StringData: Decodable {
    var array: [ArrayData]

    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()

        var result: [ArrayData] = []
        while !container.isAtEnd {
            result.append(try container.decode(ArrayData.self))
        }

        self.array = result
    }
}

CodePudding user response:

The issue is in the init(from decoder:) of StringData

If you want to keep using StringData (I guess there are more complexe data in reality?) you could do this:

var values: [ArrayData] = []
while !container.isAtEnd {
    let aValue = try container.decode(ArrayData.self)
    values.append(aValue)
}
array = values

Why?

Because the container is an unkeyedContainer, so in the same way you did:

id = try container.decode(Int.self)
cat = try container.decode(Int.self)
text = try container.decode(String.self)

It was iterating on the container.

If StringData is just for show, you can remove it and use [StringData.ArrayData].self while decoding.

  • Related