I'm using the SDWebImage plugin and I have run into the following scenario: I have two UIViewController's A and B. In UIViewControllerB I am loading a series of 10 - 15 images from the web in a UIImageView with the following code:
UIImageView *imageView = [[UIImageView alloc] init];
[imageView sd_setImageWithURL:[NSURL URLWithString:[sourceDictionary objectForKey:#"image"]]
placeholderImage:[UIImage imageNamed:#"placeholder"]];
This works well. Except that I begin downloading these images once the user loads UIViewControllerB. I was wondering if there was a way from me to begin to pre-cache or begin downloading these images while the user is still on UIViewControllerA so that when the user gets to UIViewControllerB they see a shorter delay? How would I do this in a manner so that the image isnt downloaded twice if the user switches to the second viewcontroller while a download is taking place?
Possible workaround could be to implement custom download manager using Singleton pattern, so it's available from both A and B.
Then you can track the list of image URLs requested to be downloaded as well as completed handlers to be called when download completed.
First you check that the download of the image with same URL is not taking place already and then either add image into the list and completed handler or just add new handler. You can use dictionary as a storage, using URL as a key.
Then you can use SDWebImageManager with downloadImageWithURL method, where on completed method you remove image from the list and trigger corresponding completed handlers.
So at B you know that the download has been finished. You do not necessary need to cache images manually with SDWebImageCache, let SDWebImage to do it for you automatically, so when your on completed method get called just do the same as you do, but since image has been already downloaded SDWebImage will take it from the cache. Alternatively you can send back UIImage downloaded into the completed handler.
Related
I am getting URL images from API. I have stored the UR images into string. Here my problem I want to display that into carousel. I don't know how to do this. Below is my code that I have tried.
for(int i=0;i<hotelIMAges.count;i++ )
{
NSDictionary *images=[hotelIMAges objectAtIndex:i];
NSString *Images= [images objectForKey:#"Imagepath"];
[ImageARRAy addObject:Images];
} //Here I have stored all the images into string..(https://***.jpg)
Carousel *carousel = [[Carousel alloc] initWithFrame:CGRectMake(0, 0,300, 262)];
[carousel setImages:ImagesARRAy];
You just need to process asynchronously as your current approach can be a synchronous request and blocks the main thread until that download is complete.
Consider using SDWebImage and the UIImageView extension it adds to manage the image download and display. It also supports a placeholder image that you can supply to indicate that the download is in progress.
If your using any third party carousel check for asynchronous methods to display the images.I believe setImages: method must be for images that are stored locally inside app. Do let me know if you have any queries.
----EDITED----
Your Carousel is using synchronous method to display which blocks the main thread.
You can use SDWebImage for your purpose.
For this you need to download SDWebImage for asynchronous downloading of image. You can download SDWebImage from link below.
You can use it in your Carousel.h class as
#import <SDWebImage/UIImageView+WebCache.h>
modify your setup method with below line.
[imageView sd_setImageWithURL:[NSURL URLWithString:self.images[i]]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
For details refer github page of SDwebpage. DO let me know if you have any queries.
https://github.com/rs/SDWebImage#using-asynchronous-image-downloader-independently
So, I have this news feed structure. Every news block is a custom UITableViewCell. Now, every custom cell has a CollectionView that shows images.
The problem is that when scrolling, and news cell (news block) comes out visible, the CollectionView is reloading - every time cell shows up. I'm trying to find the way to cache those images on the main ViewController side.
What would be the best approach?
If you want to avoid implementing your own cache/disk/memory handlers for this kind of job I strongly recommend either AFNetworking or SDWebImage that handle it all for you.
An example of SDWebImage on how to set an image and its cache:
[imageView sd_setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
This handles all the cache/disk/memory for you automatically.
Here is example of how you handle cache with SDWebImage:
// Set memory size limit (check with older devices to avoid memory errors when setting it to high value.)
[[SDImageCache sharedImageCache] setMaxMemoryCost:****];
// Clear disk cache
[[SDImageCache sharedImageCache] clearDiskOnCompletion:^{
}];
// Clear memory cache
[[SDImageCache sharedImageCache] clearMemory];
I would stay away from NSUserDefaults or the above mentioned example setting the images to dictionary or arrays to avoid memory errors and app crashes/performance.
You have to cache your UIImage instance, so, if you get some pictures from any source, you might write something like below:
/* some code before */
UIImage *yourImage = /* Get your UIImage from any available way */
[self.cache setObject:yourImage forKey:#"SomeUniqueID"];
/* some code after */
I guess, this code will look greater as a function, which obtains UIImage instance and it's id as parameters.
For my opinion, it's the most common way to store images. If you need a more proficient way without any overheads with third-party frameworks, you can read the documentation about NSCache.
But in general, you have a lot of different ways how to store your images:
Get the image from the disk
Get the image from the memory
Use one of the variants above, but apart them still use some lightweight & flexible frameworks, you can find a lot of on the GitHub.
So, the code I wrote above will just store images into the memory cache.
I am using SDWebImage library for handling image cache. I implemented one of its method to download image from server and populating data in tableView. Here is my code for downloading image and showing in tableViewCell
In cellForRowAtIndexPath, I did the following code
[cell.profileImageView sd_setImageWithURL:[NSURL URLWithString:url] placeholderImage:nil options:SDWebImageRefreshCached];
It works perfectly here. But when I updated image on server, the tableViewCell still shows the same image. The problem is ,its cache is not updating image. I searched with the same keywords and came across this question on StackOverflow. But couldn't resolve the issue. I also tried to clear memory and cache on viewDidDisappear
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:YES];
[[SDImageCache sharedImageCache]clearMemory];
[[SDImageCache sharedImageCache]clearDisk];
}
But its not efficient way. Is there any other way to update the cache when image on server is updated ?
You can use SDWebImageRefreshCached option to refresh concrete image, however you never know if the image was changed on the server side. So it's only your decision should you use image cache or not and when your cache should be updated.
From SDWebImage docs :
If you don't control the image server you're using, you may not be able to change the URL when its content is updated. In such case, you may use the SDWebImageRefreshCached flag. This will slightly degrade the performance but will respect the HTTP caching control headers
[imageView sd_setImageWithURL:url
placeholderImage:[UIImage imageNamed:#"placeholder.png"]
options:SDWebImageRefreshCached];
It would defeat the purpose of Image Caching if you use this in all your code. Coz the image will be downloaded everytime. Instead you could :
If you manage the server, you could setup some flags in the DB to indicate the image has changed on the server.
Implement some logic to only use SDWebImageRefreshCached once in 2 days or something like that, and use the normal code all other times.
You could also clear the entire cache once in a while to force a refresh, if that's feasible.
I have implemented SDWebImage in cellforrowatindexpath method. The problem here is when i scroll down the tableview the images are loading from web which is expected but when i scroll up the tableview the images are again downloading. What is the way to get rid of this problem. I don't want to load images from url overtime (since there is a usage limit with the web service call). I chose to use SDWebImage API for in memory cache so that once the images are loaded they are taken from cache to show it on the UI instead of making the web service call everytime. Here is my code:
[cell.placeImage sd_setImageWithURL:url placeholderImage:nil options:SDWebImageCacheMemoryOnly];
The above line is the only code in that method. Please help me.
Any kind of help is appreciated. I have seen other questions in this community but nobody said how to get an image from the cache memory.
For refreshing of the images you should use option : SDWebImageRefreshCached
[imageView sd_setImageWithURL:url placeholderImage:nil options:SDWebImageRefreshCached];
I am currently successfully using 'SDWebImageManager downloadImageWithURL' for downloading single images , followed by the delegate method 'transformDownloadedImage' automatically called upon completion to resize the images before caching them.
I would like, however, in the background to prefetch a bunch of images (~25) not yet displayed using the prefetcher code below in a similar way. However the problem is that the 'transformDownloadedImage' delegate is not called upon completion (of 1 or all the images) - images are cached as is.
SDWebImagePrefetcher *prefetcher = [SDWebImagePrefetcher sharedImagePrefetcher];
[prefetcher prefetchURLs:array progress:nil completed:^(NSUInteger completedNo, NSUInteger skippedNo) {
}];
Am I missing something? or is there some other efficient way to do this by pulling out the cached images upon completion, resizing, and reinserting? I am using "UIImage+Resize" to resize and manipulate, and obviously this needs to happen in background without blocking the UI.
Any and all advice about how to go about this efficiently will be greatly appreciated!
If you look at the implementation of SDWebImagePrefetcher you'll notice that it's using SDWebImageManager to perform the downloads, and it's available as a property. So you should be able to do something like this:
prefetcher.manager.delegate = self;
Now you can implement the downloadImageWithURL delegate method as you did before. I didn't try it but it should work.