Search code examples
iosswiftxcodeuicollectionviewuicollectionreusableview

Unable to display thumbnails in UICollectionView


I am trying to recreate this thing. I've created in Storyboard skeleton. Here's the idea of my code:

  1. Fetch images from URL's array with help of the function getThumbnailFromImage
  2. Add UIImage's with my thumbnails in array webImages
  3. Add in ViewController reusable cell MyCollectionView
  4. ...

But here I am with this))) (Don't mind absence of Auto Layout). What am I doing wrong? I think that the problem is with reloadData() but I don't know where to put it.

ViewController:

//
//  ViewController.swift
//  youtube-clone
//
//  Created by мас on 16.08.2022.
//

import Foundation
import UIKit
import YouTubePlayer
import AVFoundation

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
    
    var url: [URL?] = [
        URL(string: "https://www.youtube.com/watch?v=KhebpuFBD14"),
        URL(string: "https://www.youtube.com/watch?v=UfNdNrRHpUw"),
        URL(string: "https://www.youtube.com/watch?v=CX-BdDHW0Ho"),
        URL(string: "https://www.youtube.com/watch?v=NIOMtSzfpck")
    ]
    
    var webImages: [UIImage] = []
    
    var currentPage: Int = 0
    
    @IBOutlet var myPage: UIPageControl!
    
    @IBOutlet weak var buttonInfo: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupLayout()
        
        myPage.currentPage = 0
        myPage.numberOfPages = webImages.count
        
    }
    
    // MARK: - Collection View Setup
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return webImages.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
         
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyCollectionCell
        
        getThumbnailFromImage(url: url[indexPath.row]!, completion: { image in
            self.webImages.append(image!)
        })
        
        cell.myWebImage.image = webImages[indexPath.row]
        
        cell.myWebImage.layer.cornerRadius = 20
        
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        myPage.currentPage = indexPath.row
    }
    
    // MARK: - Layout Setup // IGNORE IT
    
    func setupLayout() {
        
        buttonInfo.layer.cornerRadius = 25
        
        buttonInfo.imageView!.transform = CGAffineTransform(rotationAngle: 180 * .pi / 180)
        
        
        self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
    }
    
    // MARK: - Videos Thumbnail Fetcher
    func getThumbnailFromImage(url: URL, completion: @escaping ((_ image: UIImage?) -> Void)) {
        
        DispatchQueue.global().async {
            let asset = AVAsset(url: url)
            let avAssetImageGenerator = AVAssetImageGenerator(asset: asset)
            avAssetImageGenerator.appliesPreferredTrackTransform = true
            
            let thumbnailTime = CMTimeMake(value: 7, timescale: 1)
            do {
                let cgThumbImage = try avAssetImageGenerator.copyCGImage(at: thumbnailTime, actualTime: nil)
                let thumbImage = UIImage(cgImage: cgThumbImage)
                
                DispatchQueue.main.async {
                    completion(thumbImage)
                }
            }
            catch {
                print(error.localizedDescription)
            }
        }
        
    }
}


Reusable Cell AKA MyCollectionCell:

import UIKit

class MyCollectionCell: UICollectionViewCell {
    
    @IBOutlet var myWebImage: UIImageView!
    
}

P.s.: YouTubePlayer is custom pod from GitHub, it's not currently used.


Solution

  • You do NOT have to use AVAssetImageGenerator, Simply you can use Youtube API to fetch the thumbnail images as .jpg image by video id, and each YouTube video has four generated images.

    https://img.youtube.com/vi/{id}/0.jpg
    https://img.youtube.com/vi/{id}/1.jpg
    https://img.youtube.com/vi/{id}/2.jpg
    https://img.youtube.com/vi/{id}/3.jpg
    

    Example https://img.youtube.com/vi/KhebpuFBD14/0.jpg

    And then it is preferred to use a third party to load this image as its displayed in a list, like https://github.com/SDWebImage/SDWebImage or https://github.com/onevcat/Kingfisher and you will NOT be worry about Concurrency or caching.