Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Image Preloading in iOS

I have developed an app which shows "full screen cards" in a UICollectionView like Tinder. The card contains an image and some text. I was loading the image using SDWebImage's sd_setImageWithURL method in the UICollectionView's cell.

However this was not giving me good performance since the images were mostly loaded when the user was on a card. I therefore used the SDWebImagePrefetcher prefetch queue to do this as follows:-

func startImagePreloadingOperationForIndex(index:Int)
{
    let numberOfImagesToBePreloadedOnEachSide = 20
    var previousIndex = index - numberOfImagesToBePreloadedOnEachSide
    var nextIndex = index + numberOfImagesToBePreloadedOnEachSide

    if previousIndex < 0
    {
        previousIndex = 0
    }
    if nextIndex >= currentNewsCollection.count
    {
        nextIndex = currentNewsCollection.count - 1
    }

    if previousIndex >= nextIndex || currentNewsCollection.isEmpty
    {
        return
    }
    let arrayOfNewsStories = currentNewsCollection[previousIndex...nextIndex]

    let arrayOfImageURLs = arrayOfNewsStories.map( { ImageUtility.getImageStringForNewsStory($0) } )

    SDWebImagePrefetcher.sharedImagePrefetcher().prefetchURLs(arrayOfImageURLs, progress: { (x, y) -> Void in
        }) { (x, y) -> Void in
    }
}

This function is called when the user lands on a particular card. The prefetching queue automatically manages not downloading images in cache so I don't have to worry about that. Along with this I am also using the sd_setImageWithURL in cellForItemAtIndexPath to pick up the downloaded image from the cache.

This is a better solution since I am now preloading images when the user is on a card. However this is a parallel queue. Which means image no. index + 20 could be loaded before the current image and the user could have to wait for the image. Also the app becomes a bit laggy if the user scrolls through over 50 cards and the memory usage also keeps on going up.

Can anyone please suggest improvements to this or a better algorithm?

Thanks

like image 929
Rajeev Bhatia Avatar asked Mar 31 '16 06:03

Rajeev Bhatia


People also ask

What is image preload?

"Preloading" loads an image file into the users' computer memory so that it can be instantly accessed when needed. This is useful, for example, if you have a mouseover event and an image needs to change without any delay.

How do you make a picture preloader?

To preload responsive images, new attributes were recently added to the <link> element: imagesrcset and imagesizes . They are used with <link rel="preload"> and match the srcset and sizes syntax used in <img> element. This kicks off a request using the same resource selection logic that srcset and sizes will apply.


2 Answers

Download the image on the current card with sd_setImageWithURL and in the completion handler start the downloading of the prefetching queue. In this way the current image always enjoys the highest priority and does not lag.

currentCardImageView.sd_setImageWithURL(url) { (image, error, imageCacheType, url) in
   // start prefetching here
}

If the current image is already downloaded SDWebImage will recognize this and fetch it from the cache.

The other issue with the lag and the high memory consumption can maybe be solved be reducing the number of prefetched image. 20 is quite high, 5 should be enough, but this depends on the image size, network speed, etc...

Another thing: SDWebImage has a maxConcurrentOperationCount property. Start with 1, test, increase to 2, test, increase... and so on. Until you find the point it lags.

like image 100
Darko Avatar answered Sep 20 '22 16:09

Darko


I'd suggest handling your own queue, saving images to disk, then loading them from disk.

Instead of an parallel queue, use a serial queue, or at least turn down the number of parallel connections

like image 39
Michael Avatar answered Sep 24 '22 16:09

Michael