I would like to ask on how to get the downloaded image after the SDWebImageManager downloaded it. I have only the code to download it via URL, here's what I got:
let manager: SDWebImageManager = SDWebImageManager.sharedManager()
manager.downloadImageWithURL(NSURL(string: feedDetails.thumbnail), options: [],
progress: {(receivedSize: Int, expectedSize: Int) -> Void in
print(receivedSize)
},
completed: {(image, error, cached, finished, url) -> Void in
self.feedImage.image = image
}
)
As far as I know (I just looked up the author's Git page) there is the following method to directly access an image which is stored inside the cache-
You can use the SDImageCache to store an image explicitly to the cache with the following code:
[[SDImageCache sharedImageCache] storeImage:myImage forKey:myCacheKey];
Where myImage is the image you want to store and myCacheKey is a unique identifier for the image.
After you stored an image to the cache and want to use that image, just do the following:
[[SDImageCache sharedImageCache] queryDiskCacheForKey:myCacheKey done:^(UIImage *image) {
// image is not nil if image was found
}];
This code is Objective-C code, you have to "convert" it to swift yourself.
I hope I could help you!
From the SDWebImageManager class the downloadImageWithURL: method
Downloads the image at the given URL if not present in cache or return
the cached version otherwise.
So if the image is present in cache you are already retrieving it with your code, instead of downloading from the web.
Thanks for answer #beeef but SDWebImage has been updated some part of code:
Save image:
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:[NSURL URLWithString:string] options:SDWebImageDownloaderUseNSURLCache progress:nil completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
if (image && finished) {
// Cache image to disk or memory
[[SDImageCache sharedImageCache] storeImage:image forKey:#"img_key" toDisk:YES completion:^{
//save
}];
}
}];
Get image from disk cache:
[[SDImageCache sharedImageCache] queryCacheOperationForKey:#"img_key" done:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) {
[self.imageV setImage: image];
}];
Related
I’m using
pod 'SDWebImage'
To download images in my application, I found that all the images were downloaded in “/Library/Caches/com.bundlename.bundlename/com.alamofire.imagedownloader/fsCachedData” with some unique names.
My app has offline support and I have managed CoreData Entity for the image with file path(files are in library caches directory), As I Upload my images my server will respond with my S3 file URL to download.
As I (the user who upload file) have an image file already but SDWebImage did not know that. So it will download the file again.
Any suggestion what should I do to manage it without downloading the same image again? I can not keep local path in my database as my app has sync function with multiple devices.
Thanks
I think you could use SDImageCache for this purpose.
Sample code:
NSArray<NSString*> *urls = #"aws s3 url here";
[[SDImageCache sharedImageCache] diskImageExistsWithKey:urls[0] completion:^(BOOL isInCache) {
if ( isInCache ) {
[yourImage setImage:[[SDImageCache sharedImageCache] imageFromDiskCacheForKey:urls[0]]];
} else {
NSURL *url = [NSURL URLWithString:item.url];
[yourImage sd_setImageWithURL:url completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
[[SDImageCache sharedImageCache] storeImage:image forKey:urls[0] toDisk:YES completion:^{
}];
[yourImage setImage:image];
}];
}
}] ;
Im using SDWebImage code, to download an image from internet.
GitHub SDWebImage
Im Doing this in Xcode 8 and Swift 3.
I want to resize it once it is downloaded, but I can't have image size until I Download the image. (To make it resize proportionally)
So, my question is, is there a way to have a completion block to execute some code when the image has finish being downloaded? I can`t seem to find on github project info about the completion of the download.
Thanks!
I Found it! Post it in case someone else needs it.
I used this to load from web
imgView.sd_setImage(with: URL(string: news.imageURL))
But for load and have a completing block I need to do:
imgView.sd_setImage(with: URL(string: news.imageURL)) { (image, error, cache, url) in
// Your code inside completion block
}
Here's some code right out of one of the SDWebImage example files, you can find more examples here: https://github.com/rs/SDWebImage/tree/master/Examples
Swift Version:
imageView.sd_setImageWithURL(NSURL(string: urlString), completed: {
(image, error, cacheType, url) in
// your code
})
Objective-C Version:
- (void)configureView
{
if (self.imageURL) {
__block UIActivityIndicatorView *activityIndicator;
__weak UIImageView *weakImageView = self.imageView;
[self.imageView sd_setImageWithURL:self.imageURL
placeholderImage:nil
options:SDWebImageProgressiveDownload
progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL *targetURL) {
if (!activityIndicator) {
[weakImageView addSubview:activityIndicator = [UIActivityIndicatorView.alloc initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]];
activityIndicator.center = weakImageView.center;
[activityIndicator startAnimating];
}
}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
[activityIndicator removeFromSuperview];
activityIndicator = nil;
}];
}
}
Hope this helps.
I am developing one app that use local database.I am getting id of image and then i am load images in UITableView using this.
[UIImage imageNamed:imageid];
The problem is what when i am populate tableview with 60 or 70 entrys the tableview scrolling is very slow.I have a more then 90 images in project folder. I want to know which is best way for fetch images faster from project properties.Please help.
First of all when you set image from local, then it should be set very quickly. But as you said that it take time then it may be because of your image size. Your image may be very heavy in the size. You can use SDWebImage to load image in synchronize mode. and make you app smoother. you can use local File URL to set image
#import "UIImageView+UIActivityIndicatorForSDWebImage.h"
When you want to set image use the below code.
NSURL *url = [NSURL fileURLWithPath:strURL];
[cell.imgCategoryIcon setImageWithURL:url usingActivityIndicatorStyle:0];
you have different option like placeholder image activityIndicator etc.
Try this:
func getDataFromUrl(url:String, completion: ((data: NSData?) -> Void)) {
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) { (data, response, error) in
completion(data: NSData(data: data))
}.resume()
}
func loadExternalImage(url:String,img:UIImageView){
getDataFromUrl(url) { data in
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
// do some task
dispatch_async(dispatch_get_main_queue(), {
img.image = UIImage(data: data!)
});
});
}
}
And this how you call:
self.loadExternalImage(<UIImage String>, img:<UIImageView Object>)
you can do it easily with SDWebImage as it keep images in cache memory. Insert files of SDWebImage and use this only
UIImageView *imgView= [[UIImageView alloc]init];
imgView.frame = CGRectMake(7, 52, 50, 50);
imgView.image=[UIImage imageNamed:#"steert_food"];
[cell.contentView addSubview: imgView];
[imgView sd_setImageWithURL:[NSURL URLWithString:_thumbnailUrl] placeholderImage:nil options:SDWebImageProgressiveDownload completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { }];
I'm using SDWebImage to download and cache images in an UITableView asynchronously but I'm having some problems.
The scenario is the following:
When the cell is created I want to load a low quality blurred image (1-2kb) from an URL, before the real image comes in. After the higher quality image is downloaded, I want to show that one.
Until now, I've tried these options, but neither one seems to work the way I expect:
1:
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:[NSURL URLWithString:lowQualityImageURL]
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize) {}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (finished) {
cell.pictureView.image = image;
[manager downloadImageWithURL:[NSURL URLWithString:highQualityImageURL]
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize) {}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (image && finished) {
[UIView transitionWithView:cell.pictureView
duration:0.1f
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
cell.pictureView.image = image;
} completion:^(BOOL finished) {
}];
}
}];
}
}];
When this code is used, the low quality image seems to be downloaded and showed before the real image, but if the user scrolls fast in the table, he will end up with wrong images for some cells (because of cell reusing - I guess). - Any solution here?
2:
[cell.pictureView sd_setImageWithURL:[NSURL URLWithString:lowQualityImageURL] placeholderImage:[UIImage new] options:SDWebImageRefreshCached completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
[cell.pictureView sd_setImageWithURL:[NSURL URLWithString:highQualityImageURL] placeholderImage:image options:SDWebImageRefreshCached completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
}];
}];
This approach seems to fix the "wrong image for cell" issue, but most of the cells end up showing their corresponding blurred image istead of the high quality image which is supposed to show.
So, to sum up, do you have an advice about how can I achieve the result I want? (download low quality image -> show it until the high quality image is downloaded -> replace it with high quality image)
LE: When using the 2nd approach I see a weird behaviour. Console output:
thumb set for cell: 1
real image set for cell: 1
thumb set for cell: 2
thumb set for cell: 3
thumb set for cell: 0
real image set for cell: 0
It appears that somehow, some of the downloads get cancelled.
I ended up using two UIImageViews, one for each photo, overlapped. When the real (big) image is completely downloaded I smoothly fade the blurred one.
Here's a helper function I wrote in Swift using Nuke:
func loadImageWithTwoQualities(lowQualityURL: NSURL, highQualityURL: NSURL, completion: (UIImage) -> () ) {
Nuke.taskWith(lowQualityURL) {
completion($0.image!)
Nuke.taskWith(highQualityURL) {
completion($0.image!)
}.resume()
}.resume()
}
You can use it with any type of image view like so:
let normalImageUrl = NSURL(string: picture)!
let largeImageUrl = NSURL(string: picture + "?type=large")!
loadImageWithTwoQualities(normalImageUrl, highQualityURL: largeImageUrl) { image in
self.someUIButton.setBackgroundImage(image, forState: .Normal)
}
I'm using SDWebImage for a while caching all my images but now i want to have more than one cache to to group various types of images. For example three kind of caches with several images each, so in runtime i want to clear one of them or have different setMaxCacheAge
Example:
types images = car images is one type, motorcycle is another... airplanes other.. like this. After i store this images i want delete or clear cache only of the motorcycle images (one type)
Now I have this but is for every images cached:
SDImageCache * sDImageCache = [SDImageCache sharedImageCache];
[sDImageCache setMaxCacheAge:60*60*24];
...
SDImageCache *imageCache = [SDImageCache sharedImageCache];
[imageCache clearMemory];
[imageCache clearDisk];
[imageCache cleanDisk];
-
I saw this but is really that i want?
SDImageCache *imageCache = [[SDImageCache alloc] initWithNamespace:#"myNamespace"];
Using Asynchronous Image Caching Independently
Ok I figure out how to do...and I will share
First i removed all evidences of [SDWebImageManager sharedManager], because I want to do everything manually.
Then [SDWebImageDownloader sharedDownloader] to request new one and queryDiskCacheForKey (SDImageCache) to get local image (disk or memory)
How:
Create new imageCache with specific namespace
self.imageCache = [[SDImageCache alloc] initWithNamespace:#"nameSpaceImageCacheXPTO"];
[_imageCache setMaxCacheAge:oneHour * 3]; // 3 hours
Check if the image (key) is already in cache if not will request new one and save later
/////////
// * Prepar Key
/////////
NSString * key = url.absoluteString;
/////////
// * Get Local Image
/////////
[_imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) {
if (image) {
completedBlock(image,nil); // return block
}else{
/////////
// * Request Image
/////////
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:url
options:SDWebImageProgressiveDownload
progress:^(NSInteger receivedSize, NSInteger expectedSize) {}
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
if (finished && image){
/////////
// * Save Image
/////////
[_imageCacheProgram storeImage:image
recalculateFromImage:NO
imageData:data
forKey:key
toDisk:YES];
completedBlock(image,error); // return block
}
}];
});
}
}];