Search code examples
iosxcodeswift3uitableviewcollectionview

CollectionView in TableViewCell scroll isn't smooth in swift3


Here is my CollectionView in TableViewCell

In my project CollectionView in TableViewCell isn't display and I added

cell.collectionView.reloadData()

in my code. After I added, CollectionView displayed in TableViewCell, but ScrollView isn't smooth. How to solve this problem. If someone have any experience or ideas help me. Thanks.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "homecell") as! HomeCategoryRowCell

    let mainThemeList = mainHomeThemeTable[(indexPath as NSIndexPath).row]

    DispatchQueue.main.async {
        cell.categoryTitle.text = mainThemeList.main_name
        cell.collectionView.reloadData()
    }


    return cell
}

CollectionView in my project,

extension HomeCategoryRowCell : UICollectionViewDataSource {

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

        debugPrint("assetsTable count \(assetsTable.count)")
        return assetsTable.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "videoCell", for: indexPath) as! HomeVideoCell

        let list = assetsTable[(indexPath as NSIndexPath).row]
        let url2 = NSURL(string:list.poster_image_url)
        let data2 = NSData(contentsOf:url2! as URL)
        //  debugPrint(list.poster_image_url)
        DispatchQueue.main.async(){
            cell.movieTitle.text = list.name
            cell.imageView.image = UIImage(data: data2! as Data)

        }

        return cell

    }

}

Solution

  • Download Image Url Data in collectionView: UICollectionView, cellForItemAt indexPath: IndexPath delegate - ASYNCHRONOUSLY

    Create a Class

    First cache the image Data with respect to key Image URL

    Why do we need to cache the data?

    Because - While scrolling we don't need to download Image Every Time so Cache the already downloaded Image Data and return the cache data

    I created a class name: AsyncImageLoader then I created a function which is a completion handler which returns the data after completion of downloading Image

    class AsyncImageLoader {
    
    static let cache = NSCache<NSString, NSData>()
    
    class func image(for url: URL, completionHandler: @escaping(_ image: UIImage?) -> ()) {
    
        DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async {
    
            if let data = self.cache.object(forKey: url.absoluteString as NSString) {
                DispatchQueue.main.async { completionHandler(UIImage(data: data as Data)) }
                return
            }
    
            guard let data = NSData(contentsOf: url) else {
                DispatchQueue.main.async { completionHandler(nil) }
                return
            }
    
            self.cache.setObject(data, forKey: url.absoluteString as NSString)
            DispatchQueue.main.async { completionHandler(UIImage(data: data as Data)) }
        }
    }
    
    } 
    

    How to use AsyncImageLoader Class?

    See below How I used in collectionView: UICollectionView, cellForItemAt indexPath: IndexPath

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
        let yourCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCollectionCell", for: indexPath) as! CustomCollectionCell
    
        yourCell.url = URL(string: "\(item_ImageUrl)")
    
       return yourCell
    }
    

    CustomCollectionCell

    class CustomCollectionCell: UICollectionViewCell {
    
    @IBOutlet weak var cellImageDisplayView: UIImageView!
    
    var url: URL? {
        didSet {
            if let url = url {
    
               cellImageDisplayView.image = nil
    
                AsyncImageLoader.image(for: url, completionHandler: { (image) in
    
                    DispatchQueue.main.async {
    
                        if let img = image {
    
                            self.cellImageDisplayView.image = img
    
    
                        }else{
                            let dummyImage = UIImage(named: "img_u")
                            self.cellImageDisplayView.image = dummyImage
                        }
                    }
    
                })
    
            }else{
    
                let dummyImage = UIImage(named: "img_u")
                self.cellImageDisplayView.image = dummyImage
    
            }
        }
     }
    
    }