skip to Main Content

I have a DetailViewController that is segued to when you click on a table view cell , the detail view shows a label , rating and a collectionView , the UICollectionView setup like this , ideally it should show two images that are downloaded and put into the image array

class DetailViewController: UIViewController , UICollectionViewDelegate , UICollectionViewDataSource{


    @IBOutlet weak var collectionView: UICollectionView!
    
    @IBOutlet weak var LabelView: UILabel!
    
    @IBOutlet weak var RatingsView: CosmosView!
    
    var mv : Result?
    
    var imgArr = [UIImage]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        LabelView.text = mv?.title
        RatingsView.rating = Double((mv!.vote_average / 2))
        
        let uri = "https://image.tmdb.org/t/p/w92" + mv!.poster_path
        downloadImage(with : uri){image in
            guard let image  = image else { return}
            self.imgArr.append(image)
        }

        let bUri = "https://image.tmdb.org/t/p/w92" + mv!.backdrop_path
        downloadImage(with : bUri){image in
            guard let image  = image else { return}
            self.imgArr.append(image)
            dump(self.imgArr)
        }
        
    }
    
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return imgArr.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
        cell.imgImage.image = imgArr[indexPath.row]
        return cell
    }
    
    func downloadImage(with urlString : String , imageCompletionHandler: @escaping (UIImage?) -> Void){
            guard let url = URL.init(string: urlString) else {
                return  imageCompletionHandler(nil)
            }
            let resource = ImageResource(downloadURL: url)
            
            KingfisherManager.shared.retrieveImage(with: resource, options: nil, progressBlock: nil) { result in
                switch result {
                case .success(let value):
                    imageCompletionHandler(value.image)
                case .failure:
                    imageCompletionHandler(nil)
                }
            }
        }

}

Here is what it looks like in storyboard , I have the proper classes and reuseIdentifiers assigned

enter image description here

But I can’t see any images for some reason
enter image description here

I have no clue why it won’t show the images , it did before I changed the layout to add a master stack view , but I can’t figure out why a minor layout change would affect , I still think i’m doing something wrong in the code. I tried adding .reloadData() and other troubleshooting but it didn’t work.
The images are downloading as seen in the output dump which prints when you segue to the detail view.

enter image description here

Please help me out.
Thanks in advance

2

Answers


  1. You should always update anything on UI on the main thread. Please add your returned image inside DispatchQueue.main.async {}

    Login or Signup to reply.
  2. Almost certainly — the problem is that the collection view loads before the images are downloaded.

    In viewDidLoad() you start an async process of downloading two images. That will take "some time" — it might take 1/4 second, 1/2 second… or it may be very quick (if they are small images) and only take 1/10th of a second.

    However, numberOfItemsInSection is probably being called at 1/100th of a second – well before the images have been downloaded.

    Change that to:

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    
        print("number of images:", imgArr.count)
        return imgArr.count
    
    }
    

    and you’ll likely see number of images: 0 as the output.

    In your completion block(s), you need to add:

    DispatchQueue.main.async {
        self.collectionView.reloadData()
    }
        
    

    Note also… those two images won’t necessarily download consecutively. If you need them in that order, you will either want to:

    • download the first image, then in its completion block start downloading the second image, or
    • start with two "placeholder" images in your imgArr and then replace them in the desired order

    In any case, you’ll still need to call .reloadData() after the images have downloaded.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search