Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slow UICollectionView with asynchronous loading

I have an UICollectionView which loads images of the iPad's memory and displays them in a grid,like Apple's Photos app. The UICollectionViewCell loads thumbnails asynchronously:

 func setImage(img:String){
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
            //load the image in the background
            let image = UIImage(contentsOfFile: img)
            //when done, assign it to the cell's UIImageView
            dispatch_async(dispatch_get_main_queue(), {
                if let imageView = self.imageView{
                    imageView.image = UIImage(contentsOfFile: img)
                }
            })
        })
    }

However, while scrolling the view lags as if it is waiting for the images to load, especially with Retina graphics. The cells and images are about 240x180px big. Is there anything wrong with the image loading above or further optimisations need to be made?

UPDATE: Time profiler results enter image description here

like image 214
Hristo Avatar asked Sep 28 '26 09:09

Hristo


2 Answers

You've already found that you're loading the UIImage again on the main queue; fixing that will help.

UIImage lazy loads its internal image data in most cases. One trick is to call its CGImage property while still on the background queue to force it to actually create its internal image data instead of lazily loading it when the image view is drawn the first time:

func setImage(img:String){
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
        //load the image in the background
        let image = UIImage(contentsOfFile: img)
        image.CGImage // <- Force UIImage to not lazy load the data
        //when done, assign it to the cell's UIImageView
        dispatch_async(dispatch_get_main_queue(), {
            if let imageView = self.imageView {
                imageView.image = image
            }
        })
   })
}

Note: If you have a lot of images you may end up getting a memory warning fairly quickly doing this. If you do, this probably won't help because the memory warning will typically cause UIImage to clear its internal image data again to free up resources.

like image 197
Mike S Avatar answered Oct 01 '26 13:10

Mike S


On the line

imageView.image = UIImage(contentsOfFile: img)

I was loading the image again on the main thread, not the image loaded asynchronously. Changed to

imageView.image = image

Scrolling is a bit better, but yet choppy. The time profiler shows similar results as before. May the bottleneck be in the UIImageView drawing? It works fine with non-retina thumbnails.

like image 20
Hristo Avatar answered Oct 01 '26 13:10

Hristo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!