具有永久缓存的sdwebimage

时间:2016-09-22 14:57:24

标签: ios sdwebimage

我正在开发一个iOS应用程序,需要SDWebImage将图片永久缓存到手机上。

  1. SDWebImage代码中存在过期设置,是否应将过期时间设置为较大值以永久存储缓存?
  2. 由于我希望图片永久缓存,我应该将它们存储到专用文件夹中还是默认目录就足够了?当应用程序关闭并重新打开以及重新启动手机时,我的应用程序需要这些图片保持持久性。
  3. 如果我想永久地缓存图片,除了将过期设置为较大值之外,还有什么我需要注意的吗?
  4. 感谢。

1 个答案:

答案 0 :(得分:3)

不幸的是SDWebImage不提供这样的功能 所以为了利用SDWebImage提供的高级缓存功能,我写了一个包装器

基本上这个类管理一个后备永久缓存,所以如果在SDWeb图像缓存中没有找到所请求的图像"磁盘和内存"它会在永久缓存中查找它 如果找到永久缓存,它将被复制到SDwebImage缓存,以便在以后的请求中使用其内存兑现

使用这种方法我设法通过SDWebImage像往常一样顺利地将图像设置到表格单元格 您还可以触发clearImageCache以在需要时删除永久缓存

.h文件

@interface CacheManager : NSObject
+ (CacheManager*)sharedManager;

// Images
- (BOOL) diskImageExistsForURL:(NSURL*) url;
- (void) downloadImage:(NSURL*) url completed:(void(^)(UIImage*))onComplete;
- (void) setImage:(NSURL*)url toImageView:(UIImageView*)iv completed:(void(^)(UIImage*))onComplete;
- (void) clearImageCache;

@end

.m文件

#import "CacheManager.h"
#import <SDWebImage/UIImageView+WebCache.h>


#define CACH_IMAGES_FOLDER      @"ImagesData"


@implementation CacheManager


static CacheManager *sharedManager = nil;

#pragma mark -
#pragma mark Singilton Init Methods
// init shared Cache singleton.
+ (CacheManager*)sharedManager{
    @synchronized(self){
        if ( !sharedManager ){
            sharedManager = [[CacheManager alloc] init];
        }
    }
    return sharedManager;
}

// Dealloc shared API singleton.
+ (id)alloc{
    @synchronized( self ){
        NSAssert(sharedManager == nil, @"Attempted to allocate a second instance of a singleton.");
        return [super alloc];
    }
    return nil;
}

// Init the manager
- (id)init{
    if ( self = [super init] ){}
    return self;
}

/**
  @returns YES if image found in the permanent cache or the cache managed by SDWebImage lib
 */
- (BOOL) diskImageExistsForURL:(NSURL*) url{

    // look for image in the SDWebImage cache
    SDWebImageManager *manager = [SDWebImageManager sharedManager];
    if([manager diskImageExistsForURL:url])
        return YES;

    // look for image in the permanent cache
    NSString *stringPath = url.path;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    return [fileManager fileExistsAtPath:stringPath];
}

/**
 get the image with specified remote url asynchronosly 
 first looks for the image in SDWeb cache to make use of the disk and memory cache provided by SDWebImage
 if not found, looks for it in the permanent cache we are managing, finally if not found in either places
 it will download it using SDWebImage and cache it.
 */
- (void) downloadImage:(NSURL*) url completed:(void(^)(UIImage*))onComplete{

    NSString *localPath = [[self getLocalUrlForImageUrl:url] path];
    NSFileManager *fileManager = [NSFileManager defaultManager];

    // -1 look for image in SDWeb cache
    SDWebImageManager *manager = [SDWebImageManager sharedManager];
    if([manager diskImageExistsForURL:url]){
        [manager downloadImageWithURL:url options:SDWebImageRetryFailed
                             progress:^(NSInteger receivedSize, NSInteger expectedSize) {}
                            completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
                                onComplete(image);

                                // save the image to the perminant cache for later
                                // if not saved before
                                if(image){
                                    if ([fileManager fileExistsAtPath:localPath]){
                                        NSURL* localeUrl = [self getLocalUrlForImageUrl:url];
                                        [self saveImage:image toCacheWithLocalPath:localeUrl];
                                    }
                                }
                            }];
        return;
    }

    // -2 look for the image in the permanent cache
    if ([fileManager fileExistsAtPath:localPath]){
        UIImage *img = [self getImageFromCache:url];
        onComplete(img);
        // save image back to the SDWeb image cache to make use of the memory cache
        // provided by SDWebImage in later requests
        [manager saveImageToCache:img forURL:url];
        return;
    }

    // -3 download the image using SDWebImage lib
    [manager downloadImageWithURL:url options:SDWebImageRetryFailed
                         progress:^(NSInteger receivedSize, NSInteger expectedSize) {}
                        completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
                            onComplete(image);
                            // save the image to the permanent cache for later
                            if(image){
                                NSURL* localeUrl = [self getLocalUrlForImageUrl:url];
                                [self saveImage:image toCacheWithLocalPath:localeUrl];
                            }
                        }];

}

- (void) setImage:(NSURL*)url toImageView:(UIImageView*)iv completed:(void(^)(UIImage*))onComplete{
    [self downloadImage:url completed:^(UIImage * downloadedImage) {
        iv.image = downloadedImage;
        onComplete(downloadedImage);
    }];
}


/**
 @param:imgUrl : local url of image to read
 */
- (UIImage*) getImageFromCache:(NSURL*)imgUrl{
    return [UIImage imageWithData: [NSData dataWithContentsOfURL:imgUrl]];
}

/**
 writes the suplied image to the local path provided
 */
-(void) saveImage:(UIImage*)img toCacheWithLocalPath:(NSURL*)localPath{
    NSData * binaryImageData = UIImagePNGRepresentation(img);
    [binaryImageData writeToFile:[localPath path] atomically:YES];
}

// Generate local image URL baesd on the name of the remote image
// this assumes the remote images already has unique names
- (NSURL*)getLocalUrlForImageUrl:(NSURL*)imgUrl{
    // Saving an offline copy of the data.
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *cachesDirectory = [paths objectAtIndex:0];
    NSString *folderPath = [cachesDirectory stringByAppendingPathComponent:CACH_IMAGES_FOLDER];
    BOOL isDir;
    // create folder not exist
    if (![fileManager fileExistsAtPath:folderPath isDirectory:&isDir]){
        NSError *dirWriteError = nil;
        if (![fileManager createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:&dirWriteError]){
            NSLog(@"Error: failed to create folder!");
        }
    }

    NSString *imgName = [[[imgUrl path] lastPathComponent] stringByDeletingPathExtension];

    NSURL *cachesDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
    NSString *pathString = [NSString stringWithFormat:@"%@/%@", CACH_IMAGES_FOLDER, imgName];
    return [cachesDirectoryURL URLByAppendingPathComponent:pathString];
}


/**
 removes the folder contating the cahced images,
 the folder will be reacreated whenever a new image is being saved to the permanent cache
 */
-(void)clearImageCache{
    // set the directory path
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *cachesDirectory = [paths objectAtIndex:0];
    NSString *folderPath =  [cachesDirectory stringByAppendingPathComponent:CACH_IMAGES_FOLDER];
    BOOL isDir;
    NSError *dirError = nil;
    // folder exist
    if ([fileManager fileExistsAtPath:folderPath isDirectory:&isDir]){
        if (![fileManager removeItemAtPath:folderPath error:&dirError])
        NSLog(@"Failed to remove folder");
    }
}

@end