-3

I want to struct my JSON array in Swift so I can use it, but everything I try throws an error. This is the JSON I'm working with:

[
      {
      "id": 15438,
      "date": "2019-05-07T03:36:51",
      "date_gmt": "2019-05-07T00:36:51",
      "type": "post",
      "title": {
      "rendered": "Title Here"
      }
    }
 ]

And this is the code I'm using:

struct getTitle: Decodable {
  let title: [Title]
}

struct Title: Decodable {
  let rendered: String?
}

class ViewController: NSViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    let jsonUrlString = "URL HERE"
    guard let url = URL(string: jsonUrlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, err) in

        guard let data = data else { return }

        do {
            let titleresult = try JSONDecoder().decode(getTitle.self, from: data)
            print(titleresult)

        } catch let jsonErr {
            print("Error serializing json:", jsonErr)
        }
      }.resume()
    }
  }

The error it's throwing is:

Error serializing json: typeMismatch(Swift.Dictionary<Swift.String, 
Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: 
"Expected to decode Dictionary<String, Any> but found an array 
instead.", underlyingError: nil))

I already tried using

JSONDecoder().decode([getTitle].self, from: data)

to make it an array, but that throws the same error but turned around. It expected an array but found a dictionary.

I'm not sure what the problem is here. I already tried following multiple guides but they all result in the same thing. It's probably something with the struct I'm doing wrong but I don't know what.

Roan
  • 29
  • 2
  • 8
  • 1
    `let title: [Title]` — `title` is not an array in your JSON – user28434'mstep May 07 '19 at 10:05
  • Possible duplicate of [Swift4 JSONDecoderExpected to decode Dictionary but found an array instead](https://stackoverflow.com/questions/49720958/swift4-jsondecoderexpected-to-decode-dictionarystring-any-but-found-an-array) – Victor Sanchez May 07 '19 at 10:19
  • You are reading the error message backwards, the decoder expects a dictionary but you're giving it an array. – Joakim Danielson May 07 '19 at 10:35

3 Answers3

2

Please read the error messages carefully and entirely, they are extremely descriptive.

Expected to decode Dictionary but found an array instead

means the found object is an array. So the fix

JSONDecoder().decode([getTitle].self, from: data)

is basically right. But the subsequent error is quite different

...codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "title", intValue: nil)], debugDescription: "Expected to decode Array but found a dictionary instead."

Please notice the codingPath, it can be read like a key path [0].title: The value for key title in the first item of the root array is not an array, so change the struct to

struct getTitle: Decodable {
    let title: Title
}

Reading JSON is very easy: {} is dictionary which becomes a struct, [] is array.

Finally please name structs with starting capital letter.

vadian
  • 274,689
  • 30
  • 353
  • 361
  • Thanks! Sorry I didn't look good enough at your previous answer. This was the solution indeed. – Roan May 07 '19 at 10:40
  • @Roan the solutions is given 18 mins before this answer , this is a stupid mistake of you not ones who gave correct answers before – Shehata Gamal May 07 '19 at 10:53
1

Try with this:

struct getTitle: Decodable {
  let title: Title
}

struct Title: Decodable {
  let rendered: String?
}

class ViewController: NSViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    let jsonUrlString = "URL HERE"
    guard let url = URL(string: jsonUrlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, err) in

        guard let data = data else { return }

        do {
            let titleresult = try JSONDecoder().decode([getTitle].self, from: data)
            print(titleresult)

        } catch let jsonErr {
            print("Error serializing json:", jsonErr)
        }
      }.resume()
    }
  }
iDevid
  • 507
  • 3
  • 13
0

You have a root array with title is a dictionary not array

struct getTitle: Codable { 
    let title: Title 
}

struct Title: Codable {
    let rendered: String
}

let titleresult = try JSONDecoder().decode([getTitle].self, from: data)
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • You're just changing the name and putting it in brackets right? That doesn't change the behavior of the code except it reverses the error. When in brackets it expects an array but finds a dictionary. – Roan May 07 '19 at 10:24
  • 1
    title is a dictionary with `{}` and top root is an array with `[]` – Shehata Gamal May 07 '19 at 10:28
  • Copy the answer as it is the name doesn't matter , but you should start struct names with capital letter – Shehata Gamal May 07 '19 at 10:29