0

This is the code I am using but I am unable to fetch the JSON.

Error message:

Expected to decode Dictionary<String, Any> but found an array instead.

func getMovieByName(completion: @escaping (Bool, Any?, Error?) -> Void) {
    guard let url = URL(string:"https://api.themoviedb.org/3/search/movie?api_key=4cb1eeab94f45affe2536f2c684a5c9e&query='star") else { return }

    let session = URLSession.shared
    let task = session.dataTask(with: url) { (data, _, _) in
        guard let data = data else { return  }
        do {
            let items = try JSONDecoder().decode(ItemList.self, from: data)

            DispatchQueue.main.async {
                completion(true, items, nil)
            }
        } catch {
            DispatchQueue.main.async {
                completion(false, nil, error)
            }
        }
    }
    task.resume()
}

JSON:

{
    "page": 1,
    "total_results": 2102,
    "total_pages": 106,
    "results": [{
        "vote_count": 9052,
        "id": 11,
        "video": false,
        "vote_average": 8.2,
        "title": "Star Wars",
        "popularity": 31.502792,
        "poster_path": "/btTdmkgIvOi0FFip1sPuZI2oQG6.jpg",
        "original_language": "en",
        "original_title": "Star Wars",
        "genre_ids": [
            12,
            28,
            878
        ],
        "backdrop_path": "/4iJfYYoQzZcONB9hNzg0J0wWyPH.jpg",
        "adult": false,
        "overview": "Princess Leia is captured and held hostage by the evil Imperial forces in their effort to take over the galactic Empire. Venturesome Luke Skywalker and dashing captain Han Solo team together with the loveable robot duo R2-D2 and C-3PO to rescue the beautiful princess and restore peace and justice in the Empire.",
        "release_date": "1977-05-25"
    }]
}

struct Results: Codable    {
    let id: Int
    let title: String
    let poster_path: String


struct ItemList: Codable {
    let results: Results
}

}
General Grievance
  • 4,555
  • 31
  • 31
  • 45
BigMac
  • 49
  • 6
  • Update your question with your `ItemList` struct and any other nested structs used to parse the data. – rmaddy Jun 24 '18 at 02:20
  • And review [these search results](https://stackoverflow.com/search?q=Expected+to+decode+Dictionary+but+found+an+array+instead) on the error. – rmaddy Jun 24 '18 at 02:21
  • As I said, update your question. Don't put code in comments. – rmaddy Jun 24 '18 at 02:48
  • 1
    The error message is pretty clear. (Learn to) **Read** the JSON. It's very simple. There are only two collection types, array (`[]`) and dictionary (`{}`). And then read the error message again. It should even tell you the coding path where the error occurs. – vadian Jun 24 '18 at 04:39

2 Answers2

1

You can create a Swift Struct for this purpose. Here is how you do it.

import Foundation

struct MovieStruct: Codable {
    let page, totalResults, totalPages: Int?
    let results: [Result]?

    enum CodingKeys: String, CodingKey {
        case page
        case totalResults = "total_results"
        case totalPages = "total_pages"
        case results
    }
}

struct Result: Codable {
    let voteCount, id: Int?
    let video: Bool?
    let voteAverage: Double?
    let title: String?
    let popularity: Double?
    let posterPath, originalLanguage, originalTitle: String?
    let genreIDS: [Int]?
    let backdropPath: String?
    let adult: Bool?
    let overview, releaseDate: String?

    enum CodingKeys: String, CodingKey {
        case voteCount = "vote_count"
        case id, video
        case voteAverage = "vote_average"
        case title, popularity
        case posterPath = "poster_path"
        case originalLanguage = "original_language"
        case originalTitle = "original_title"
        case genreIDS = "genre_ids"
        case backdropPath = "backdrop_path"
        case adult, overview
        case releaseDate = "release_date"
    }
}

After you have created the struct, you can do something like this to parse your data.

func getMovieByName(completion: @escaping (Bool, Any?, Error?) -> Void) {
    guard let url = URL(string:"https://api.themoviedb.org/3/search/movie?api_key=4cb1eeab94f45affe2536f2c684a5c9e&query='star") else { return }

    let session = URLSession.shared
    let task = session.dataTask(with: url) { (data, _, _) in
        guard let data = data else { return  }
        do {
            let items = try? JSONDecoder().decode(MovieStruct.self, from: jsonData)

            DispatchQueue.main.async {
                completion(true, items, nil)
            }
        } catch {
            DispatchQueue.main.async {
                completion(false, nil, error)
            }
        }
    }
    task.resume()
}

Note I have created the struct with the JSON which you have given. I hope it helps.

Rizwan Ahmed
  • 919
  • 13
  • 19
0
func getMovieByName(completion: @escaping (Bool, Any?, Error?) -> Void) {
    guard let url = URL(string:"https://api.themoviedb.org/3/search/movie?api_key=4cb1eeab94f45affe2536f2c684a5c9e&query='star") else { return }

    let session = URLSession.shared
    let task = session.dataTask(with: url) { (data, _, _) in
        guard let data = data else { return  }
        do {
            let items = try JSONDecoder().decode(Result.self, from: data)

            DispatchQueue.main.async {
                completion(true, items, nil)
            }
        } catch {
            DispatchQueue.main.async {
                completion(false, nil, error)
            }
        }
    }
    task.resume()
}

Result struct contains the contents of "results"

struct Result: Codable {
    var results: [Movie]
}

Add variables to correspond to the item's fields

struct Movie: Codable {
    var id: Int
    var vote_count: Int
    var title: String

    //etc..
}
Nader
  • 1,120
  • 1
  • 9
  • 22
  • Thanks for your help. I am able to get one object. But I can not get a dictionary displayed. This is what I have done: //gets one object let result = try JSONDecoder().decode(Result.self, from: data) print(result.title as Any) //unable to get the dictionary let result = try JSONDecoder().decode([Result].self, from: data) for obj in result { print(obj.title as Any) } – BigMac Jun 24 '18 at 12:15
  • try `result.results.title' because you are returning a `Result` object – Nader Jun 24 '18 at 14:37