Swift Codable expected to decode Dictionary<String, Any>but found a string/data instead

user7219266 picture user7219266 · Oct 30, 2017 · Viewed 13k times · Source

I have been working with the Codable protocol

Here is my JSON file :

    {  
   "Adress":[  

   ],
   "Object":[  
      {  
         "next-date":"2017-10-30T11:00:00Z",
         "text-sample":"Some text",
         "image-path":[  
            "photo1.png",
            "photo2.png"
         ],
         "email":"[email protected]",
         "id":"27"
      },
      {  
         "next-date":"2017-10-30T09:00:00Z",
         "text-sample":"Test Test",
         "image-path":[  
            "image1.png"
         ],
         "email":"[email protected]",
         "id":"28"
      }
   ]
}

I only have to focus on the Object array, and the "image-path" array can contain 0, 1, or 2 strings.

So here is my implementation:

struct Result: Codable {
    let Object: [MyObject]
}

struct MyObject: Codable {

    let date: String
    let text: String
    let image: [String]
    let email: String
    let id: String

    enum CodingKeys: String, CodingKey {
        case date = "next-date"
        case text = "text-sample"
        case image = "image-path"
        case email = "email"
        case id = "id"
    }

    init() {
        self.date = ""
        self.text = ""
        self.image = []
        self.email = ""
        self.id = ""
    }
}

I call it from my service class after requesting and getting the JSON data this way:

if let data = response.data {
                let decoder = JSONDecoder()
                let result = try! decoder.decode(Result, from: data)
                dump(result.Object)
            }

Everything is working except the [String] for the image property

But it can't compile, or I get an "Expected to decode..." error.

How should I handle the nil/no data scenario?

Answer

PGDev picture PGDev · Oct 30, 2017

I have made a small change in your MyObject struct, i.e.,

1. Marked all properties as optionals

2. Removed init() (I don't think there is any requirement of init() here.)

3. Use Result.self instead of Result in decoder.decode(...) method

struct MyObject: Codable
{
    let date: String?
    let text: String?
    let image: [String]?
    let email: String?
    let id: String?

    enum CodingKeys: String, CodingKey
    {
        case date = "next-date"
        case text = "text-sample"
        case image = "image-path"
        case email = "email"
        case id = "id"
    }
}

To test the above, I have used the below code and it is working fine.

    let jsonString = """
        {"Adress": [],
        "Object": [{"next-date": "2017-10-30T11:00:00Z",
        "text-sample": "Some text",
        "image-path": ["photo1.png", "photo2.png"],
        "email": "[email protected]",
        "id": "27"},
      {"next-date": "2017-10-30T09:00:00Z",
       "text-sample": "Test Test",
       "image-path": ["image1.png"],
       "email": "[email protected]",
       "id": "28"}
       ]
        }
    """
    if let data = jsonString.data(using: .utf8)
    {
        let decoder = JSONDecoder()
        let result = try? decoder.decode(Result.self, from: data) //Use Result.self here
        print(result)
    }

This is the result value that I am getting:

enter image description here