Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Main thread blocking on scroll and Kingfisher setting the image

I've been running down slow scroll performance and I've noticed that when I scroll and setImage gets called with non-cached images, the performance lags while the download happens.

if let imageURL = URL(string: presentable.imageUrl) {
    let resource = ImageResource(downloadURL: imageURL)
    photoView.kf.setImage(with: resource, options: [.transition(.fade(0.2))])
}

My understanding is that Kingfisher downloads these on a background thread and then displays them on the main thread but the main thread seems to be temporarily blocked. Removing the .transition doesn't help the situation.

Any ideas on how to improve my scroll performance? Thanks

like image 262
Zack Shapiro Avatar asked Jan 07 '19 21:01

Zack Shapiro


2 Answers

When the images are larger than the image view, iOS needs to manipulate large UIImage objects, which can cause observable stuttering in the UI. You can prevent that problem by resizing the images before using them.

Fortunately, Kingfisher has a processor that can resize these (in a background thread) for you. As the Cheat Sheet says:

Using DownsamplingImageProcessor for high resolution images

Think about the case we want to show some large images in a table view or a collection view. In the ideal world, we expect to get smaller thumbnails for them, to reduce downloading time and memory use. But in the real world, maybe your server doesn't prepare such a thumbnail version for you. The newly added DownsamplingImageProcessor rescues [sic]. It downsamples the high-resolution images to a certain size before loading to memory:

imageView.kf.setImage(
    with: resource,
    placeholder: placeholderImage,
    options: [
        .processor(DownsamplingImageProcessor(size: imageView.size)),
        .scaleFactor(UIScreen.main.scale),
        .cacheOriginalImage
    ])

Typically, DownsamplingImageProcessor is used with .scaleFactor and .cacheOriginalImage. It provides a reasonable image pixel scale for your UI, and prevent future downloading by caching the original high-resolution image.

I created a little test with small images and confirmed that it was silky smooth, but when I used large images, I experienced stuttering in the scrolling behavior. But when I added this DownsamplingImageProcessor in the large image scenario, it was silky smooth again.

like image 82
Rob Avatar answered Nov 07 '22 15:11

Rob


Updating

self.imageView.contentMode = .scaleAspectFill

to

self.imageView.contentMode = .scaleAspectFit

did the trick for me.

I have embedded UICollectionView inside UITableViewCell. Each UICollectionViewCell has an image view which loads image from URL using Kingfisher. My table view scrolling was a lot jerky and I tried different things including not to bind model and setting data to each cell. But nothing made any difference whatsoever. Once I changed content mode of image view, it is now scrolling very smoothly.

As per Rob's answer, it is also possible that setting mode to .scaleAspectFill might be required to do some processing even-though the image size is smaller (even 480 x 320 in my case). After updating mode to .scaleAspectFit, now its scrolling smoothly even for large-sized images.

like image 1
NSPratik Avatar answered Nov 07 '22 14:11

NSPratik