Abrcd18
Abrcd18

Reputation: 185

How to properly display parsed data in table view after receiving them through completion handler

I need to show info about movies(taken from https://developers.themoviedb.org/) in tableView. I'm doing network request using a singleton and then pass parsed data to tableViewController through completion handler. I can print received data but I can't properly set them in tableView cell. Could you please help me how to fix this problem.

Network Manager

func getMovies(completion: @escaping ([Movies]?) -> Void) {
    
guard let url = URL(string: "https://api.themoviedb.org/3/movie/now_playing?api_key=\(apiKey)&language=en")
else { fatalError("Wrong URL") }
    
URLSession.shared.dataTask(with: url) { (data, response, error) in
    
     if let jsonData = data {
        let decoder = JSONDecoder()
     do {
        let moviesResult = try decoder.decode(MoviesResult.self, from: jsonData)
        let movies = moviesResult.results
        completion(movies)
        }
     catch {
            print(error)
          }
    }
}.resume()

}

Movies View Controller

var movies = [Movies]()
    
  override func viewDidLoad() {
        super.viewDidLoad()
   
        network.getMovies { result in
            if let result = result {
                self.movies = result
                print(self.movies)
            }
        }

extension MoviesViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return movies.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let movie = movies[indexPath.row]
        print(movie)
        
        if let cell = tableView.dequeueReusableCell(withIdentifier: "moviesMainInfo", for: indexPath) as? MovieTableViewCell {
            
            cell.filmTitle.text = movie.title
            cell.filmRating.text = String(movie.popularity!)
            return cell
          }
        return UITableViewCell()
    }
}

Parsed result: [MovieApp.Movies(genreIDs: Optional([14, 28, 12]), overview: Optional("Wonder Woman comes into conflict with the Soviet Union during the Cold War in the 1980s and finds a formidable foe by the name of the Cheetah."), popularity: Optional(1927.057), title: Optional("Wonder Woman 1984"), releaseDate: Optional("2020-12-16"), posterPath: Optional("/8UlWHLMpgZm9bx6QYh0NFoq67TZ.jpg")),

Upvotes: 0

Views: 108

Answers (1)

πter
πter

Reputation: 2217

You are doing everything correctly, you just need to reload your UITableView when data arrives. Be aware that you need to reload your UITableView on the main thread, because UIKit isn't thread safe:

otherwise your application will most probably crash:

private func reloadTableView() {
    DispatchQueue.main.async {
        self.tableView.reloadData()
    }
}

Also I encourage you to extract your networking function from viewDidLoad. An other improvement is to use [weak self] in your closures to avoid memory leaks:

private func loadData() {
    network.getMovies { [weak self] result in
        if let result = result {
            self?.movies = result
            print(self?.movies)
            self?.reloadTableView()
        } else {
            // Maybe show some info that the data could not be fetched
        }
    }
}

And in your viewDidLoad just call it:

override func viewDidLoad() {
    super.viewDidLoad()
    loadData()
}

Upvotes: 1

Related Questions