// // XHWebImageAutoSizeCache.m // XHWebImageHeightLayoutExample // // Created by zhuxiaohui on 2016/11/16. // Copyright © 2016年 it7090.com. All rights reserved. // https://github.com/CoderZhuXH/XHWebImageAutoSize #import "XHWebImageAutoSizeCache.h" #import "NSString+XHWebImageAutoSize.h" #import "XHWebImageAutoSizeConst.h" @interface XHWebImageAutoSizeCache() @property(nonatomic,strong)NSCache * memCache; @property(nonnull,strong)NSFileManager *fileManager; @end @implementation XHWebImageAutoSizeCache +(XHWebImageAutoSizeCache *)shardCache{ static XHWebImageAutoSizeCache *instance = nil; static dispatch_once_t oneToken; dispatch_once(&oneToken,^{ instance = [[XHWebImageAutoSizeCache alloc] init]; }); return instance; } - (instancetype)init{ self = [super init]; if (self) { self.memCache = [[NSCache alloc] init]; self.fileManager = [NSFileManager defaultManager]; } return self; } -(BOOL)storeImageSize:(UIImage *)image forKey:(NSString *)key{ if(!image || !key) return NO; CGSize imgSize = image.size; NSDictionary *sizeDict = @{@"width":@(imgSize.width),@"height":@(imgSize.height)}; NSData *data = [self dataFromDict:sizeDict]; NSString *keyName = key.sizeKeyName; [self.memCache setObject:data forKey:keyName]; return [self.fileManager createFileAtPath:[self sizeCachePathForKey:keyName] contents:data attributes:nil]; } -(void)storeImageSize:(UIImage *)image forKey:(NSString *)key completed:(XHWebImageAutoSizeCacheCompletionBlock)completedBlock{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ BOOL result = [self storeImageSize:image forKey:key]; dispatch_async(dispatch_get_main_queue(), ^{ if(completedBlock){ completedBlock(result); } }); }); } -(BOOL)storeReloadState:(BOOL)state forKey:(NSString *)key{ if(!key) return NO; NSString *stateString = @"0"; if(state) stateString = @"1"; NSDictionary *stateDict = @{@"reloadState":stateString}; NSData *data = [self dataFromDict:stateDict]; NSString *keyName = key.reloadKeyName; [self.memCache setObject:data forKey:keyName]; return [self.fileManager createFileAtPath:[self reloadCachePathForKey:keyName] contents:data attributes:nil]; } -(void)storeReloadState:(BOOL)state forKey:(NSString *)key completed:(XHWebImageAutoSizeCacheCompletionBlock)completedBlock{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ BOOL result = [self storeReloadState:state forKey:key]; dispatch_async(dispatch_get_main_queue(), ^{ if(completedBlock){ completedBlock(result); } }); }); } -(CGSize)imageSizeFromCacheForKey:(NSString *)key{ NSString *keyName = key.sizeKeyName; NSData *data = [self dataFromMemCacheForKey:keyName]; if(!data){ data = [self dataFromDiskCacheForKey:keyName isSizeCache:YES]; } NSDictionary *sizeDict = [self dictFromData:data]; CGFloat width = [sizeDict[@"width"] floatValue]; CGFloat height = [sizeDict[@"height"] floatValue]; CGSize size = CGSizeMake(width, height); return size; } -(BOOL)reloadStateFromCacheForKey:(NSString *)key{ NSString *keyName = key.reloadKeyName; NSData *data = [self dataFromMemCacheForKey:keyName]; if(!data){ data = [self dataFromDiskCacheForKey:keyName isSizeCache:NO]; } NSDictionary *reloadDict = [self dictFromData:data]; NSInteger state = [reloadDict[@"reloadState"] integerValue]; if(state ==1) return YES; return NO; } #pragma mark - XHWebImageAutoSizeCache (private) -(NSData *)dataFromMemCacheForKey:(NSString *)key{ return [self.memCache objectForKey:key]; } -(NSData *)dataFromDiskCacheForKey:(NSString *)key isSizeCache:(BOOL)isSizeCache{ NSString *path = [self sizeCachePathForKey:key]; if(!isSizeCache) path =[self reloadCachePathForKey:key]; if ([self.fileManager fileExistsAtPath:path isDirectory:nil] == YES) { return [self.fileManager contentsAtPath:path]; } return nil; } -(NSData *)dataFromDict:(NSDictionary *)dict{ if(dict==nil) return nil; NSError *error; NSData *data =[NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error]; if (error) { XHDebugLog(@"ERROR, faild to get json data"); return nil; } return data; } -(NSDictionary *)dictFromData:(NSData *)data{ if(data==nil) return nil; return [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; } -(NSString *)sizeCachePathForKey:(NSString *)key{ return [self cachePathForKey:key inPath:[self sizeCacheDirectory]]; } -(NSString *)reloadCachePathForKey:(NSString *)key{ return [self cachePathForKey:key inPath:[self reloadCacheDirectory]]; } - (NSString *)cachePathForKey:(NSString *)key inPath:(NSString *)path { [self checkDirectory:path]; return [path stringByAppendingPathComponent:key]; } -(NSString *)sizeCacheDirectory{ return [[self baseCacheDirectory] stringByAppendingPathComponent:@"SizeCache"]; } -(NSString *)reloadCacheDirectory{ return [[self baseCacheDirectory] stringByAppendingPathComponent:@"ReloadCache"]; } -(NSString *)baseCacheDirectory{ NSString *pathOfLibrary = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]; NSString *path = [pathOfLibrary stringByAppendingPathComponent:@"XHWebImageAutoSizeCache"]; return path; } -(void)checkDirectory:(NSString *)path { BOOL isDir; if (![self.fileManager fileExistsAtPath:path isDirectory:&isDir]) { [self createBaseDirectoryAtPath:path]; } else { if (!isDir) { NSError *error = nil; [self.fileManager removeItemAtPath:path error:&error]; [self createBaseDirectoryAtPath:path]; } } } - (void)createBaseDirectoryAtPath:(NSString *)path { __autoreleasing NSError *error = nil; [self.fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error]; if (error) { XHDebugLog(@"create cache directory failed, error = %@", error); } else { [self addDoNotBackupAttribute:path]; } } - (void)addDoNotBackupAttribute:(NSString *)path { NSURL *url = [NSURL fileURLWithPath:path]; NSError *error = nil; [url setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error]; if (error) { XHDebugLog(@"error to set do not backup attribute, error = %@", error); } } @end