28

Hello I am using the SDWebImage framework in a project and I want to download and cache images, but I think my code is storing an image in the cache twice? Is there any way to store the image in the cache by a key only once? Here is my code.

         SDWebImageManager *manager = [SDWebImageManager sharedManager];
         [manager downloadWithURL:[NSURL URLWithString:url] options:0 progress:^(NSUInteger receivedSize, long long expectedSize) {

          } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {

            if(image){
                NSString *localKey = [NSString stringWithFormat:@"Item-%d", i];
                [[SDImageCache sharedImageCache] storeImage:image forKey:localKey];
            }

          }];  

Is there something that I missed? Looks like doing this in my allocations instrument is pilling up a lot of memory.

Mike Beeler
  • 4,081
  • 2
  • 29
  • 44
AgnosticDev
  • 1,843
  • 2
  • 20
  • 36

11 Answers11

32

I'm surprised nobody answered this question, but I've had a similar question and came across this, so I'll answer it for people viewing this going forward (assuming you've sorted this out yourself by now).

To directly answer your question, yes, you are caching the image twice.

Download calls to SDWebImageManager automatically cache images with keys based on the absoluteString of the image's url. If you want your own key, you can use the download call on SDWebImageDownloader which as far as I can tell does NOT cache by default. From there you can call the sharedImageCache as you're already doing and cache with whatever key you want.

That aside, it is strange you're seeing allocations piling up in any case as SDWebImage likes to cache to disk and not memory generally. Maybe something else is going on at the same time?

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Stakenborg
  • 2,890
  • 2
  • 24
  • 30
  • do you mean if we set key for each (fixed downloading image url), it will not going to fire downloading event on network ? right ? and will it use previous caching ? – kalpesh jetani Nov 28 '13 at 07:09
  • Been a while since I looked at this, but if you are planning on storing an image with a specific cache key, you should check the `[SDImageCache sharedImageCache]` for the image before making a download request. If you don't have it, store it with your specific key so it will be there next time. This may have changed by now, but you should use `SDWebImageDownloader` and then store with your own key if you're going to do it this way. – Stakenborg Dec 02 '13 at 14:50
25

In Swift use the code below to download an image and to store it in the cache:

//SDWebImageManager download image with High Priority 

    SDWebImageManager.sharedManager().downloadImageWithURL(NSURL(string: imageUrl), options: SDWebImageOptions.HighPriority, progress: { (receivedSize :Int, ExpectedSize :Int) in
            SVProgressHUD.show()
            }, completed: { (image :UIImage!, error:NSError!, cacheType :SDImageCacheType, finished :Bool,imageUrl: NSURL!) in
                if(finished) {
                    SVProgressHUD.dismiss()
                    if((image) != nil) {
                        //image downloaded do your stuff
                    }
                }
        })

Swift 3 version:

SDWebImageManager.shared().downloadImage(with: NSURL(string: "...") as URL!, options: .continueInBackground, progress: { 
(receivedSize :Int, ExpectedSize :Int) in

}, completed: { 
(image : UIImage?, error : Error?, cacheType : SDImageCacheType, finished : Bool, url : URL?) in

})

Objective-C version:

[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:[NSURL URLWithString:imageUrl] 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:CUSTOM_KEY toDisk:YES];     
                    }
                }]; 
yuchen
  • 408
  • 3
  • 9
parth
  • 853
  • 11
  • 18
  • Thank you parth. I have not looked into the Swift version yet, but does the Swift version have an SDWebImageDownloader class implementation to cache your image with a custom key instead of the URL? – AgnosticDev Nov 24 '16 at 20:40
  • Yes swift version have class to cache your image with custome key. You can use below code, SDImageCache.sharedImageCache().storeImage(image, forKey: "\(file.attachmentFileName!)_\(file.fileId)") – parth Nov 25 '16 at 09:07
  • 1
    Awesome! Cached image with custom key finally. – yuchen Jan 19 '17 at 03:23
  • With the latest version of `SDWebImage` 5.0, this doesn't work. The `SDWebImageManager.shared` doesn't have that method – Rikh Sep 01 '20 at 19:32
16

SWIFT 5 & Latest SDWebImage 5.2.3

SDWebImageManager.shared.loadImage(
    with: album.artUrlFor(imageShape: .square),
    options: .continueInBackground, // or .highPriority
    progress: nil,
    completed: { [weak self] (image, data, error, cacheType, finished, url) in
        guard let sself = self else { return }

        if let err = error {
            // Do something with the error
            return
        }

        guard let img = image else {
            // No image handle this error
            return
        }

        // Do something with image
    }
)
DoesData
  • 6,594
  • 3
  • 39
  • 62
11

Swift 4:

SDWebImageManager.shared().loadImage(
        with: URL(string: imageUrl),
        options: .highPriority,
        progress: nil) { (image, data, error, cacheType, isFinished, imageUrl) in
          print(isFinished)
}
Bogdan Bystritskiy
  • 1,325
  • 12
  • 10
5

SDWebImage caches the image both to disk as well as memory. Let's go through this:

  1. You download the image from a new url.
  2. It gets cached to memory and disk.
  3. If you call the image in the same session, it is retrieved from the memory.
  4. Let's say you re-run the app and then access the url, it will check the memory, where the image won't be there, then it will check the disk, and get it from there. If not, it will download it.
  5. The image stays in disk for a week by the standard setting.

So, you don't need to worry about caching. SDWebImage takes care of it pretty damn well.

You can do custom implementation for caching as well as image refresh from the cache in case you want the settings as per your HTTP caching header as well.

You can find the complete details on their github page here.

Gautam Jain
  • 2,913
  • 30
  • 25
5

Swift 4.0.

let url = URL(string: imageUrl!)

SDWebImageManager.shared().imageDownloader?.downloadImage(with: url, options: .continueInBackground, progress: nil, completed: {(image:UIImage?, data:Data?, error:Error?, finished:Bool) in
     if image != nil {. 

     }
})
Nimantha
  • 6,405
  • 6
  • 28
  • 69
reza_khalafi
  • 6,230
  • 7
  • 56
  • 82
4

Try APSmartStorage (https://github.com/Alterplay/APSmartStorage) instead of SDWebImage.

APSmartStorage gets data from network and automatically caches data on disk or in memory in a smart configurable way. Should be good enough for your task.

slatvick
  • 1,207
  • 2
  • 16
  • 25
1

Yes is possible to download the image using SDWebImage And store into local memory Manually.

Downloaded Image store into local memory using SDWebImage

func saveImage(url: URL, toCache: UIImage?, complation: @escaping SDWebImageNoParamsBlock) {
    guard let toCache = toCache else { return }

    let manager = SDWebImageManager.shared()
    if let key = manager.cacheKey(for: url) {
        manager.imageCache?.store(toCache, forKey: key, completion: complation)
    }
}

Load image from memory using image URL

static func imageFromMemory(for url: String) -> UIImage? {
    if let encoded = url.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed),
        let url = URL(string: encoded) {
        let manager = SDWebImageManager.shared()
        if let key: String = manager.cacheKey(for: url),
            let image = manager.imageCache?.imageFromMemoryCache(forKey: key) {
            return image
        }
    }
    return nil
}
AshvinGudaliya
  • 3,234
  • 19
  • 37
0

//CREATE A CUSTOME IMAGEVIEW AND PASS THE IMAGE URL BY ARRAY(INDEXPATH.ROW)

(void) loadImage:(NSString *)imageLink{

    imageLink = [imageLink stringByReplacingOccurrencesOfString:@" " withString:@"%20"];

    SDWebImageManager *manager = [SDWebImageManager sharedManager];

    [manager loadImageWithURL:[NSURL URLWithString:imageLink] options:SDWebImageDelayPlaceholder progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {

    } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {

        imageFrame.image = image;

    }];
}
Petter Friberg
  • 21,252
  • 9
  • 60
  • 109
Slimshady
  • 21
  • 3
0

Swift 5.1

import UIKit
import SDWebImage

extension UIImageView{
    func downloadImage(url:String){
      //remove space if a url contains.
        let stringWithoutWhitespace = url.replacingOccurrences(of: " ", with: "%20", options: .regularExpression)
        self.sd_imageIndicator = SDWebImageActivityIndicator.gray
        self.sd_setImage(with: URL(string: stringWithoutWhitespace), placeholderImage: UIImage())
    }
}

How to use

let myUrl = "https://www.example.com"
myImageView.downloadImage(url: myUrl)

Rashid Latif
  • 2,809
  • 22
  • 26
-1
SDWebImageManager *manager = [SDWebImageManager sharedManager];

[manager downloadImageWithURL:ImageUrl options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize)

{


} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {

    if(image){


        NSLog(@"image=====%@",image);
    }
}];
Bhavin Bhadani
  • 22,224
  • 10
  • 78
  • 108