May Phyu
May Phyu

Reputation: 905

UICollection is very slow in showing Image with Swift 3

I'm using UICollectionView to show the images in my app.
The problem is that it takes very slow to show images. After 50 seconds, the images in collection view appears. :(
When I find the solution in google, mostly they write the following codes.
But it is not work for me.

  cell.layer.shouldRasterize = true
  cell.layer.rasterizationScale = UIScreen.main.scale

and

extension SeeAllCollectionView {

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    debugPrint("seeAllLIStCell Count \(assetsTable.count)")
    return assetsTable.count
}

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


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

    let list = assetsTable[(indexPath as NSIndexPath).row]


    var imageName: String? = (list.poster_image_url)
    var image: UIImage? = (images_cache[imageName!])
    if image != nil {
        debugPrint("Yes Image")

        cell.imageView.image = image

    } else{
        debugPrint("NO Image")
        cell.imageView.image = nil

        DispatchQueue.main.async(){
            let url = NSURL(string: list.poster_image_url)
            let data = NSData(contentsOf:url! as URL)
            var image = UIImage(data: data as! Data)
            DispatchQueue.main.async(execute: {() -> Void in
                cell.movieTitle.text = list.name
                cell.imageView?.image = image
            })
            self.images_cache[imageName!] = image
        }

    }




    return cell
}

}


// MARK: - UICollectionViewDelegate

extension SeeAllCollectionView {

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

            debugPrint("Selected")


    let list = assetsTable[(indexPath as NSIndexPath).row]
    debugPrint(list.poster_image_url)
    debugPrint(list.name)

    prefs.set(list.poster_image_url, forKey: "poster_image_url")
    prefs.set(list.name, forKey: "name")
    prefs.set(list.assets_id, forKey: "VIDEO_ID")
    prefs.set(false, forKey: "FLAG")
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let vc = storyboard.instantiateViewController(withIdentifier: "DetailsChannel") as UIViewController
            self.present(vc, animated: true, completion: nil)

}

}

Here is my screenshot when I run the project. I got these many lines of codes when I run.

enter image description here

Please anyone help me how should I do?

Upvotes: 1

Views: 1599

Answers (3)

Wladek Surala
Wladek Surala

Reputation: 2629

this line:

DispatchQueue.main.async()

upon downloading image is probably causing the error, it blocks the main thread and executes network requests on main (UI) queue, not to mention the fact that these requests are then performed serially (therefore slow). Try to change the snippet to:

DispatchQueue.global.async(qos: DispatchQoS.QoSClass.background){
        let url = NSURL(string: list.poster_image_url)
        let data = NSData(contentsOf:url! as URL)
        var image = UIImage(data: data as! Data)
        DispatchQueue.main.async(execute: {() -> Void in

where global stands for global queue default for such network operations.

EDIT: apart from using main queue for network calls there may be an issue with actually too many images loaded for rows which are not currently visible on the screen. If there are lot of them and connection is not-so-good you will end up with app pending downloads for onscreen cells. Consider lazy loading images only for onscreen cells - and cancelling downloads for rows which are not visible. There is a quite good tutorial (however for table view, but you can easily extend it for collection) in Swift on how to accomplish this.

Upvotes: 0

Bhavik
Bhavik

Reputation: 209

You can give an attempt to SDWebimage All async Thread operations maintained well.

That can provide following advantages

Asynchronously download

Auto Purging Image Cache if memory warnings happen for the app

Image URL caching

Image Caching

Avoid Duplicate Downloads

You can directly use a single method in cell as below

[cell.storeImg sd_setImageWithURL:[NSURL URLWithString:strURL] placeholderImage:kDefaultImageForDisplay];

In your code following line should creates problem as that operation can happen on main thread let data = NSData(contentsOf:url! as URL)

Upvotes: 0

dahiya_boy
dahiya_boy

Reputation: 9503

I got the same console error when I am getting the data from the API call and reload the UITableView (as per my requirement). My issue is solved by using

DispatchQueue.global(qos: .background).async { // load data in back ground mode so that main thread can be safed.
let url = NSURL(string: list.poster_image_url)
            let data = NSData(contentsOf:url! as URL)
            var image = UIImage(data: data as! Data)
    DispatchQueue.main.async(execute: {
                                cell.movieTitle.text = list.name
                cell.imageView?.image = image
                            }) 
self.images_cache[imageName!] = image       
        }

Screen Shot of Error I got on my Console Before

enter image description here

Upvotes: 1

Related Questions