Search code examples
jsonswiftapidecode

Store TMDB API data


I'm working on an app that requires the use of the TMDB API. I have been trying to store the results from the API in a struct but it keeps giving me the error:

No exact matches in call to subscript

This is the struct:

struct MovieList: Codable {
    let dates: Date?
    let page: Int?
    let results: [Result]?
    let total_pages: Int?
    let total_results: Int?
}

struct Result: Codable {
    let adult: Bool?
    let backdrop_path: String?
    let genre_ids: [Int]?
    let id: Int?
    let original_language: String?
    let original_title: String?
    let overview: String?
    let popularity: Int?
    let poster_path: String?
    let release_date: String?
    let title: String?
    let video: Bool?
    let vote_average: Float?
    let vote_count: Int?

And here is my API call:

public class LoadTMDBData {

  var tmdbMoviesData = [[Result]]()

init() {
  getTMDBData()
}

func getTMDBData() {
    guard let url = URL(string: "") else {
          fatalError("Invalid URL")
      }
    // Set session configuration to default
    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)
    let task = session.dataTask(with: url) { data, response, error in
      
      // Check that data has been returned
      guard let data = data else { return }
      do {
        let tmdbData = try JSONDecoder().decode([MovieList].self, from: data)
        self.tmdbMoviesData = tmdbData["result"]
      }
      catch{
        let error = error
        print(error.localizedDescription)
      }
    }
  // execute the HTTP request
  task.resume()
}

Solution

  • When using a struct you don't access its properties using a string key like ["someProperty"], instead you use dot notation .someProperty, so to get the results property you do

    let results = myMoveList.results
    

    What makes it a little more complicated here is that you have, as you properly have coded for, an array of MovieList and that you want to extract all results into an array for array.

    For this you can use a high order function map to do this

    self.tmdbMoviesData = tmdbData.map(\.results)
    

    but since results is optional we use a similar function that will filter out any nil values, compactMap

    self.tmdbMoviesData = tmdbData.compactMap(\.results)
    

    Another comment, you have made all properties optional in your structs and while this is an easy way forward it might lead to hiding some decoding issues and more cumbersome code when using the types. I would recommend not to use optional unless really needed.