-2

This is my first time using the swift 4 codable protocol in an app.

I'm given a json response like this -

{
  "result": [
    {
      "id": 1,
      "heading": "Chapter 1",
      "headingTextColor": "#3e9690",
      "title": "Introduction: inovation for crisis",
      "coverImage": "https://www.country067.com/wp-content/uploads/sites/28/2017/07/logoImage_4.jpg",
      "descriptionUrl": "This is an option attribute. If not null this chapter will probably has no sections",
      "sections": [
        {
          "id": 1,
          "title": "Background",
          "url": "http://api.example.com/chapter/1/section/1",
          "projects": "null"
        },
        {
          "id": 2,
          "title": "Projects",
          "url": null,
          "projects": [
            {
              "id": 1,
              "title": "Support to refugees",
              "url": "http://api.example.com/chapter/1/project/1",
              "coverImage": "https://example/wp-content/uploads/sites/28/2017/07/logoImage_4.jpg"
            },
            {
              "id": 2,
              "title": "title text",
              "url": "http://api.example.com/chapter/1/project/2",
              "coverImage": "https://example.com/wp-content/uploads/sites/28/2017/07/logoImage_4.jpg"
            }
          ]
        }
      ]
    }
  ]
}

Using the decodable protocol, i created my models to map the response .

struct ChapterResult: Decodable {
    let result: [Chapter]
}
struct Chapter: Decodable {
    let id: Int
    let heading: String
    let headingTextColor: String
    let title: String
    let coverImage: String
    let descriptionUrl: String
    let sections: [Section]
}

struct Section: Decodable {
    let id: Int
    let title: String
    let url: String?
    let projects: [Project]?
}

struct Project: Decodable {
    let id: Int
    let title: String
    let url: String
    let coverImage: String
}

When calling the json decoder I do the following

let decoder = JSONDecoder()
let response = try decoder.decode(ChapterResult.self, from: data)
completion(.success(response.result))

which then results in the following error

failure(Optional(Error Domain=NSCocoaErrorDomain Code=4864 "Expected to decode Array but found a string/data instead." UserInfo={NSCodingPath=( "CodingKeys(stringValue: \"result\", intValue: nil)", "_JSONKey(stringValue: \"Index 0\", intValue: 0)", "CodingKeys(stringValue: \"sections\", intValue: nil)", "_JSONKey(stringValue: \"Index 0\", intValue: 0)", "CodingKeys(stringValue: \"projects\", intValue: nil)"

ielyamani
  • 17,807
  • 10
  • 55
  • 90
stringRay2014
  • 636
  • 1
  • 11
  • 29
  • In the first case `"projects": "null"`, projects is a `String`, in the second one it's an Array. So `let projects: [Project]?` will fails on the first one, but succeed on the second one. You need a custom init to prevent that. – Larme Oct 27 '18 at 09:54

3 Answers3

2

It says result[0].sections[0].projects has a TypeMissMatch error. So this "projects": "null" should be an array but it's string.

Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
-1

Read the error:

Expected to decode Array but found a string/data instead

In your JSON file projects have String or Array:

"projects": "null"

"projects": [
{
    "id": 1

To fix the issue "null" should be null. If you can't edit JSON file you should write custom initializer.

Daniil Subbotin
  • 6,138
  • 5
  • 20
  • 24
-1

see, Accroding to your struct

struct Section: Decodable {
let id: Int
let title: String
let url: String?
let projects: [Project]? 

}

projects is a array of type project.

{
      "id": 1,
      "title": "Background",
      "url": "http://api.example.com/chapter/1/section/1",
      "projects": "null"
    }

But at 0th index of sections, the value of projects key is "null" which is a string, so that's why you are getting an error.

Now read carefully your error it contains "Expected to decode Array but found a string/data instead."

krishan kumar
  • 378
  • 6
  • 11