Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ImageView with webp take more time to fetch disk image when app Re-enter foreground #2227

Closed
Swapnil-Jagtap opened this issue Feb 23, 2018 · 18 comments

Comments

@Swapnil-Jagtap
Copy link

New Issue Checklist

Issue Info

Info Value
Platform Name e.g. iOS
Platform Version e.g. 9.0 and above
SDWebImage Version e.g. 4.3.0
Integration Method cocoapods
Xcode Version Xcode 9
Repro rate e.g. all the time (100%)

Issue Description and Steps

SDWebImage will clear memory cache when app enter background. So, when app enter foreground,
on reloadData, imageView in cell will flicker for jpg images and take more time to load for webp images(If I am not wrong it will take more time to decode webp images), even though cached data haven't changed. I am straggling with webp images, Is their is any way around it to fetch images from disk with no flicker.

[cell.cellImageView sd_setImageWithURL:[NSURL URLWithString:toolsModel.thumbImgUrl] placeholderImage:[UIImage imageNamed:@"background"] options:SDWebImageRefreshCached|SDWebImageRetryFailed];

Steps around reloadData:
show image before reloadData;
find image in SD memory cache, and not found;
find image in SD disk cache, get it async;
load disk image complete and show.

@dreampiggy
Copy link
Contributor

dreampiggy commented Feb 23, 2018

@swapnil-vuclip No flicker, means to sync load. Since this will decode on main queue, UIKit will not run into another runloop to acutally render your placeholder(or nil to clear). You can consider using SDWebImageQueryDiskSync to sync load, though this may decrease the frame rate. See description there :)

More over, actually that clear memory cache when entering background not so accurate. We only clear memory when memory warning and remove outdated disk cache when entering background. If your application has already suspend and stay in background, then user open more Apps and a memory warning trigger, only this time your application become active, then receive the memory warning and clear the memory cache to avoid your application be killed with a high priority. This is different from that we clear memory cache each time you entering the background :)

Also, there are another option. We can keep a global weak NSMapTable for all image instance.(Do not impact the retain count to increase memory usage.) So when memory warning, even the NSCache was purged, your UIImageView.image is alive, so we can get this as from memory cache to allow rendering. And then sync back this alive image to NSCache again.

This performance enhancement is scheduled to be done in 5.x, but if user really need this, we can put back in 4.x

@Swapnil-Jagtap
Copy link
Author

@dreampiggy Thanks for your reply and detailed description on same, Adding the SDWebImageQueryDiskSync worked perfectly for me along with SDWebImageRefreshCached so whenever their is change in server image sdk will fetch and update latest one in disk cache.

Updated Code :
[cell.cellImageView sd_setImageWithURL:[NSURL URLWithString:toolsModel.thumbImgUrl] placeholderImage:[UIImage imageNamed:@"background"] options: SDWebImageQueryDiskSync|SDWebImageRefreshCached|SDWebImageRetryFailed];

Also thanks for version 4.3.1 available with improvement on Cache.

@dreampiggy
Copy link
Contributor

You're welcome :)

@Swapnil-Jagtap
Copy link
Author

I struggling with one issue related to as we discussed in above thread, When I test with sample app where I added 4-5 UIImageView and load both the format images (jpg & webp) from server, performance wise work fine for me.
But when we try with our own app where we load more than 100 thumbnails in my UITableView having list of horizontal image view collection, I face few issue listed below
1] With WebP images :

  • using SDWebImageQueryDiskSync as option on every kill and relaunch the app or on Re-enter foreground images would be render up-front as they fetch from disk, but scrolling is not smooth, there is noticeable jerk in the cells until scroll all the way down then after no jerk observed for that session.
  • Not using SDWebImageQueryDiskSync as option, not seen any jerk smooth scroll but every time app render all images(even they cached) and it will take noticeable time to load on image view.

2] With jpg images :

  • using SDWebImageQueryDiskSync as option on every kill and relaunch the app or on Re-enter foreground images would be render up-front with smooth scroll, there is jerk but not easily noticeable in the cells.
  • Not using SDWebImageQueryDiskSync as option, not seen any jerk smooth scroll but on kill and relaunch the app will take time to render images and after few ms render all images at once.

@dreampiggy specially need your help on WebP front

@Swapnil-Jagtap Swapnil-Jagtap reopened this Mar 7, 2018
@dreampiggy
Copy link
Contributor

dreampiggy commented Mar 7, 2018

@swapnil-vuclip The only difference between JPEG and WebP is the decoding time. In general, WebP decoding spend 5x time slower than JPEG(Real device on ARM64 platform, not iPhone Simulator).

So, I can provide some advice for this. One simple solution is to provide a transition animation when you load the image from disk cache. This can avoid those visual effect. Maybe some cases you can try this to "solve the problem".

For other solution, such as use mmap (Through diskReadingOptions) to speed up query disk speed; This can not solve this problem from the stractch because the image instance is not in memory at all for your case.

Maybe in 5.x I can introduce a cache-serializer to allow you save the modified data instead of original data. Then you can just encode the WebP images to JPEG images after download. This can speed up the decoding speed.

However, since you load the image from disk, there must be duration unlike memory cache, this is un-avoidable :)

@Swapnil-Jagtap
Copy link
Author

When I try with transition gives me that error
screen shot 2018-03-07 at 10 35 06 pm

@Swapnil-Jagtap
Copy link
Author

one more how to use in my case NSDataReadingMappedIfSafe in diskCacheReadingOptions

@dreampiggy
Copy link
Contributor

You should import "UIView+WebCache.h" when using Objective-C. Or import the umbrella headers.

Since many user argue for this "cache serializer" feature and it's not API-breaking. I'm considering add this into 4.x in patch version....

@dreampiggy
Copy link
Contributor

@swapnil-vuclip See #2245. If you are facing the issue of WebP decoding speed from disk cache. You can considerate to encode the image to another format such like JPEG or PNG when storing to disk cache.

@dreampiggy dreampiggy added this to the 4.3.3 milestone Mar 8, 2018
@Swapnil-Jagtap
Copy link
Author

When would available 4.3.3 via pod?

@dreampiggy
Copy link
Contributor

dreampiggy commented Mar 8, 2018

As soon as those 4.3.3 milstone merged. Maybe this weekend.

@Swapnil-Jagtap
Copy link
Author

@dreampiggy Thanks for #2245, I replace both .h&.m files for SDWebImageManager in my pod project but still facing few issues
@dreampiggy can you plz provide some help on below concern

  • Is their any code change required in my own image loader singleton class where I had method to load Async images from server

screen shot 2018-03-08 at 12 33 38 pm

, to encode the image to another format such like JPEG or PNG when storing to disk cache.
  • I still notice jerk on both JPEG & WebP when I used SDWebImageQueryDiskSync, scroll more jerky on WebP stuck many time, also tried as you suggested using transition animation but again it will not help us. Are those jerk avoidable.

  • Related transition animation it shows only first time load images then after it wont shows me animation when we relaunch and re-enter foreground as they load from memory or disk

  • specifically with JPEG as I mentioned early, Not using SDWebImageQueryDiskSync as option, not seen any jerk smooth scroll but on kill and relaunch the app will take time almost 4-5sec to render images and after that time render all images at once.

@dreampiggy
Copy link
Contributor

dreampiggy commented Mar 8, 2018

@swapnil-vuclip 😅 There is no magic way to solve this. Because your application was killed or anyway that cause your memory cache invalid. You now have to query disk cache. However, query disk cache need time to first load NSData into memory, then need time to decode it into a UIImage to render on UIImageView. You can not remove this cost because it's the objective facts cost. But can only decrease the time duration for those two cases.

For disk data time, you can use NSDataReadingMappedIfSafe on SDImageCache.shared.cacheConfig.diskReadingOptions. This will use mmap instead of fread and maybe enhance the performance.

For decoding time, WebP decoding spend 5x time than JPEG, so I create that PR to allow user to convert the original WebP data from the server to JPEG format and store to cache. Then you just need to decoding JPEG from disk cache.

If this duration still not face your limit, you have to find other ways to reduce this visual effect. For example, you can provide placeholder image, add indicator, using view transition...and so on.

For that view transition, it was designed to use after download because most time we do not need any transition for image from disk cache. We have one SDWebImageForceTransition to force enable transition, but I think this is not what you need :)

@Swapnil-Jagtap
Copy link
Author

Swapnil-Jagtap commented Mar 8, 2018

@dreampiggy Agreed and thanks for detailed description, how to use/set NSDataReadingMappedIfSafe on SDImageCache.shared.cacheConfig.diskReadingOptions in my case
Can I only set that like this ?

SDImageCache *imgCache = [[SDImageCache alloc] init];
imgCache.config.diskCacheReadingOptions = NSDataReadingMappedIfSafe;
                                       OR
SDWebImageManager *manager = [SDWebImageManager sharedManager];
manager.imageCache.config.diskCacheReadingOptions = NSDataReadingMappedIfSafe;

imageView.sd_imageTransition = SDWebImageTransition.fadeTransition;
[imageView sd_setImageWithURL:imgUrl
                         placeholderImage:nil options:SDWebImageRetryFailed|SDWebImageRefreshCached];

@dreampiggy
Copy link
Contributor

dreampiggy commented Mar 8, 2018

If you want this config applied for all the view category request, set the config to [SDImageCache sharedCache]. And then just use sd_setImageWithURL:

If not(only apppied for current batch of image request), you should now use a little tricky way by using the API in UIView+WebCache, there is a context arg and you can pass a new SDWebImageManager instance.

Though this looks suck. In 5.x we will introduce this context arg to all view category because of SDWebImageOptions is a Objective-C enum, and it's just a NSUInteger which unlike the one in Swift that you can bind associate object on it... :)

SDImageCache *imgCache = [[SDImageCache alloc] init];
imgCache.config.diskCacheReadingOptions = NSDataReadingMappedIfSafe;
SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:imgCache downloader:SDWebImageDownloader.sharedDownloader];
imageView.sd_imageTransition = SDWebImageTransition.fadeTransition;
[imageView sd_internalSetImageWithURL:imgUrl placeholderImage:nil options:SDWebImageRetryFailed|SDWebImageRefreshCached operationKey:nil setImageBlock:nil progress:nil completed:nil context:@{SDWebImageExternalCustomManagerKey : manager}];

@dreampiggy
Copy link
Contributor

#2245 Merged and 4.3.3 released

@Swapnil-Jagtap
Copy link
Author

@dreampiggy Thanks for 4.3.3 release,
For WebP loading to convert the original WebP data from the server to JPEG format and store to cache. how to change the config to store the encoded image into disk cache instead of the original data from the server.

@dreampiggy
Copy link
Contributor

dreampiggy commented Mar 13, 2018

@swapnil-vuclip See the documents there:

 SDWebImageManager.sharedManager.cacheKeyFilter = ^NSData * _Nullable(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL) {
    SDImageFormat format = [NSData sd_imageFormatForImageData:data];
    switch (format) {
        case SDImageFormatWebP:
            return image.images ? data : nil; // return nil means let `SDImageCache` to automatically choose the data, currently implementation is based on alpha channel, PNG for alpha channel image and JPEG for non-alpha channel image
        default:
            return data;
    }
 };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants