Home > Enterprise >  Displaying the Image From API using DidSelectRow
Displaying the Image From API using DidSelectRow

Time:02-16

I am trying to send the data in including image from one view controller to another . The data is fetching from API . The data is successfully loaded into first view controller including image but when I try to reuse same code with didSelectRow function I am getting following errors . Cannot assign value of type 'Data?' to type 'UIImage' . The error on this line dc.imagemovie = presenter.getImageData(by: row). Here is the code to fetch the data from API.

class MoviePresenter: MoviePresenterProtocol {
    
    private let view: MovieViewProtocol
    private let networkManager: NetworkManager
    private var movies = [Movie]()
    private var cache = [Int: Data]()
    var rows: Int {
        return movies.count
    }
    
    init(view: MovieViewProtocol, networkManager: NetworkManager = NetworkManager()) {
        self.view = view
        self.networkManager = networkManager
    }
    
    
    func getMovies() {
        let url = "https://api.themoviedb.org/3/movie/popular?language=en-US&page=3&api_key=6622998c4ceac172a976a1136b204df4"
        
        networkManager.getMovies(from: url) { [weak self] result in
            switch result {
            case .success(let response):
                self?.movies = response.results
                self?.downloadImages()
                DispatchQueue.main.async {
                    self?.view.resfreshTableView()
                }
            case .failure(let error):
                
                DispatchQueue.main.async {
                    self?.view.displayError(error.localizedDescription)
                }
            }
        }
    }
    
    func getTitle(by row: Int) -> String? {
        return movies[row].originalTitle
    }
    
    func getOverview(by row: Int) -> String? {
        return movies[row].overview
    }
    
    func getImageData(by row: Int) -> Data? {
        return cache[row]
    }
    
    private func downloadImages() {
        let baseImageURL = "https://image.tmdb.org/t/p/w500"
        let posterArray = movies.map { "\(baseImageURL)\($0.posterPath)" }
        
        let group = DispatchGroup()
        group.enter()
        for (index, url) in posterArray.enumerated() {
            networkManager.getImageData(from: url) { [weak self] data in
                if let data = data {
                    self?.cache[index] = data
                }
            }
        }
        group.leave()
        group.notify(queue: .main) { [weak self] in
            self?.view.resfreshTableView()
        }
    }
     
    
}

Here is the code in view controller to display the data into table view cell .

class MovieViewController: UIViewController {
    
    
    @IBOutlet weak var userName: UILabel!
    @IBOutlet weak var tableView: UITableView!
    
    private var presenter: MoviePresenter!
    
    var finalname = ""
    
    
    override func viewDidLoad() {
        super.viewDidLoad()

        userName.text = "Hello: "   finalname
        setUpUI()
        
       // configure presenter
       presenter = MoviePresenter(view: self)
        presenter.getMovies()
    }
    private func setUpUI() {
        tableView.dataSource = self
        tableView.delegate = self
    }
    
    
    @IBAction func selectSegment(_ sender: UISegmentedControl) {
        
        if sender.selectedSegmentIndex == 0{
        setUpUI()
        presenter = MoviePresenter(view: self)
        presenter.getMovies()
        }
    }
    
}

extension MovieViewController: MovieViewProtocol {
    
    func resfreshTableView() {
        tableView.reloadData()
    }
    
    func displayError(_ message: String) {
        let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
        let doneButton = UIAlertAction(title: "Done", style: .default, handler: nil)
        alert.addAction(doneButton)
        present(alert, animated: true, completion: nil)
    }
    
}

extension MovieViewController: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        presenter.rows
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: MovieViewCell.identifier, for: indexPath) as! MovieViewCell
        
        let row = indexPath.row
        let title = presenter.getTitle(by: row)
        let overview = presenter.getOverview(by: row)
        let data = presenter.getImageData(by: row)
        cell.configureCell(title: title, overview: overview, data: data)
        return cell
    }
    
   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let dc = storyboard?.instantiateViewController(withIdentifier: "MovieDeatilsViewController") as! MovieDeatilsViewController
        
        let row = indexPath.row
       dc.titlemovie = presenter.getTitle(by: row) ?? ""
       dc.overview = presenter.getOverview(by: row) ?? ""
       **dc.imagemovie = presenter.getImageData(by: row)** 
      
        self.navigationController?.pushViewController(dc, animated: true)
   }
    
    
}


extension MovieViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
}

Here is the code for display the data .

class MovieDeatilsViewController: UIViewController {
    
    
    @IBOutlet weak var movieImage: UIImageView!
    
    @IBOutlet weak var movieTitle: UILabel!
    
    @IBOutlet weak var movieOverview: UILabel!
    
    
    var titlemovie = ""
    var overview = ""
    var imagemovie = UIImage()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        movieTitle.text = titlemovie
        movieOverview.text = overview
        movieImage.image = imagemovie
        
    }

}




 

CodePudding user response:

You need to return UIImage :

class MoviePresenter: MoviePresenterProtocol {

...
    // Convert data to UIImage
    func getImageData(by row: Int) -> UIImage? {
        return UIImage(data: cache[row])
    }

You need yo use UIImage and UIImage view to configure cell :

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCell(withIdentifier: MovieViewCell.identifier, for: indexPath) as! MovieViewCell
    
        let row = indexPath.row
        let title = presenter.getTitle(by: row)
        let overview = presenter.getOverview(by: row)
        let image = presenter.getImageData(by: row)
        // cell is now configured with an image
        cell.configureCell(title: title, overview: overview, image: image)
        return cell
    }

You need to modify cell.configureCell to handle UIImage? instead of data.

When selecting a cell you must use UIImage to init VC :

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let dc = storyboard?.instantiateViewController(withIdentifier: "MovieDeatilsViewController") as! MovieDeatilsViewController
    
    let row = indexPath.row
    dc.titlemovie = presenter.getTitle(by: row) ?? ""
    dc.overview = presenter.getOverview(by: row) ?? ""
    dc.imagemovie = presenter.getImageData(by: row)// now an image
  
    self.navigationController?.pushViewController(dc, animated: true)
}

Use UIImage to initialise image movie in detail vc :

class MovieDeatilsViewController: UIViewController {
    @IBOutlet weak var movieImageView: UIImageView! // Image view here
    @IBOutlet weak var movieTitle: UILabel!
    @IBOutlet weak var movieOverview: UILabel!

    var titlemovie = ""
    var overview = ""
    var imagemovie : UIImage?

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated: animated)

        movieTitle.text = titlemovie
        movieOverview.text = overview
        // here you could also display a default image
        // if image is not set
        if let image = imagemovie {
            movieImageView.image = image
        }
    
    }

}
  • Related