BigMac
BigMac

Reputation: 49

Unable to get Dictionary from JSON

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
}

}

Upvotes: 0

Views: 118

Answers (2)

Rizwan Ahmed
Rizwan Ahmed

Reputation: 958

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.

Upvotes: 1

Nader
Nader

Reputation: 1148

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..
}

Upvotes: 0

Related Questions