0

I am attempting to create a Tinder for Movies app where the movies are loaded in using The Movie Database API and I am using Koloda pod for the card swiping features. I have run into a problem where I have to implement a Koloda datasource method where I have to return a UIView (which will be presented on the card).

The issue is that I would like to retrieve the image from the database and it might make the app slow if I were to load all the images beforehand, so I would like to retrieve each image when needed. This causes an error as retrieving the image is asynchronous and despite using completion handlers, I run into an issue where I cannot return a value from within a closure, as it still requires a return value outside the closure. But if I were to provide another return value outside the closure, this return statement always gets triggered and I cannot return the image I want to retrieve. Meaning I will always return the noImageAvailable image. May I know how to solve this issue? Thanks!

    func koloda(_ koloda: KolodaView, viewForCardAt index: Int) -> UIView {
    
    let movie = movies[index]
    let poster = movie.posterImage
    var imageView = UIImageView(image: UIImage(named: "noImageAvailable"))
    
    guard let posterString = poster else {
        return imageView
    }
    
    let urlString = "https://image.tmdb.org/t/p/w300" + posterString
    
    guard let posterImageURL = URL(string: urlString) else {
        return imageView
    }
    
    
    getImageDataFrom(url: posterImageURL) { image in
        DispatchQueue.main.async {
            imageView = UIImageView(image: image)

        }
    }
    
    return imageView
    
}


private func getImageDataFrom(url: URL, handler: @escaping (UIImage) -> Void) {
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        // Handle Error
        if let error = error {
            print("DataTask error: \(error.localizedDescription)")
            return
        }
        
        guard let data = data else {
            // Handle Empty Data
            print("Empty Data")
            return
        }
        
        if let image = UIImage(data: data) {
            handler(image)
        } else {
            handler(UIImage(named: "noImageAvailable")!)
        }
    }.resume()
}
user844288
  • 17
  • 1
  • 6
  • I don't know the software but the method `viewForCardAt` looks like a datasource method which is called by the framework. You have to load the image on controller level – because it's asynchronous – and then tell the datasource to reload. – vadian Jul 09 '21 at 06:55
  • @vadian I'm assuming you mean I should all the images and store them in an array first, so I can return it from images[index] in viewForCardAt. The issue is that my database has around 10000 movies, so I think doing that would make the app freeze. Is there any way to load images as I go, depending on the index registered by viewForCardAt? – user844288 Jul 09 '21 at 10:19
  • No, I don’t mean that, but you need an asynchronous download manager which loads each image on demand and updates the card on completion. – vadian Jul 09 '21 at 10:46
  • @vadian Sorry I am rather new to asynchronous code and Swift, how would I go about incorporating that into my code? Any advice would be helpful, thank you! – user844288 Jul 09 '21 at 10:48
  • There are libraries like [Kingfisher](https://github.com/onevcat/Kingfisher) – vadian Jul 09 '21 at 10:50

0 Answers0