XHCacheManager.m 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. //
  2. // XHCacheManager.m
  3. // XHImageViewer
  4. //
  5. // Created by 曾 宪华 on 14-2-18.
  6. // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
  7. //
  8. #import "XHCacheManager.h"
  9. #import "XHFileAttribute.h"
  10. #import "UIImage+Utility.h"
  11. #import "NSString+XHMD5.h"
  12. @interface XHCacheManager () {
  13. NSCache *_memoryCache;
  14. NSString *_cacheDirectoryPath;
  15. }
  16. @property (nonatomic, strong) NSString *identifier;
  17. @end
  18. @implementation XHCacheManager
  19. + (instancetype)shareCacheManager {
  20. return self.manager;
  21. }
  22. + (XHCacheManager *)cacheManagerWithIdentifier:(NSString *)identifier {
  23. return [[XHCacheManager alloc] initWithIdentifier:identifier];
  24. }
  25. - (id)init {
  26. return self.class.manager;
  27. }
  28. + (XHCacheManager *)manager {
  29. static XHCacheManager *sharedInstance = nil;
  30. static dispatch_once_t onceToken;
  31. dispatch_once(&onceToken, ^{
  32. sharedInstance = [[XHCacheManager alloc] initWithIdentifier:NSStringFromClass(self)];
  33. });
  34. return sharedInstance;
  35. }
  36. - (id)initWithIdentifier:(NSString *)identifier {
  37. if(identifier.length <= 0) {
  38. return self.class.manager;
  39. }
  40. self = [super init];
  41. if(self) {
  42. _memoryCache = [NSCache new];
  43. _memoryCache.countLimit = 50;
  44. self.identifier = identifier;
  45. }
  46. return self;
  47. }
  48. - (void)dealloc {
  49. [_memoryCache removeAllObjects];
  50. }
  51. #pragma mark- Uitility
  52. + (void)_checkWorkspace:(NSString*)rootDir
  53. {
  54. BOOL isDirectory = NO;
  55. BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:rootDir isDirectory:&isDirectory];
  56. if(!exists || !isDirectory){
  57. [[NSFileManager defaultManager] createDirectoryAtPath:rootDir withIntermediateDirectories:YES attributes:nil error:nil];
  58. }
  59. for(int i=0; i<16; i++) {
  60. for(int j=0; j<16; j++) {
  61. NSString *subDir = [NSString stringWithFormat:@"%@/%X%X", rootDir, i, j];
  62. isDirectory = NO;
  63. exists = [[NSFileManager defaultManager] fileExistsAtPath:subDir isDirectory:&isDirectory];
  64. if(!exists || !isDirectory){
  65. [[NSFileManager defaultManager] createDirectoryAtPath:subDir withIntermediateDirectories:YES attributes:nil error:nil];
  66. }
  67. }
  68. }
  69. }
  70. #pragma mark- directory operation
  71. - (NSString *)_cacheDirectory {
  72. if(_cacheDirectoryPath == nil){
  73. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
  74. _cacheDirectoryPath = [paths.lastObject stringByAppendingPathComponent:self.identifier.MD5Hash];
  75. [self.class _checkWorkspace:_cacheDirectoryPath];
  76. }
  77. return _cacheDirectoryPath;
  78. }
  79. - (NSArray *)_fileAttributesInWorkSpace {
  80. NSString *rootDir = self._cacheDirectory;
  81. NSMutableArray *files = [NSMutableArray array];
  82. for(int i=0; i<16; i++) {
  83. for(int j=0; j<16; j++) {
  84. NSString *subDir = [NSString stringWithFormat:@"%@/%X%X", rootDir, i, j];
  85. NSArray *list = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:subDir error:nil];
  86. for(id name in list) {
  87. NSString *filePath = [NSString stringWithFormat:@"%@/%@", subDir, name];
  88. NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
  89. if(attr) {
  90. [files addObject:[[XHFileAttribute alloc] initWithPath:filePath attributes:attr]];
  91. }
  92. }
  93. }
  94. }
  95. return files;
  96. }
  97. - (NSString *)_pathForHash:(NSString *)hash {
  98. return [NSString stringWithFormat:@"%@/%@/%@", [self _cacheDirectory], [hash substringToIndex:2], hash];
  99. }
  100. #pragma mark- Caching control
  101. - (void)limitNumberOfCacheFiles:(NSInteger)numberOfCacheFiles {
  102. NSArray *list = [self _fileAttributesInWorkSpace];
  103. NSSortDescriptor *dsc = [NSSortDescriptor sortDescriptorWithKey:@"fileModificationDate" ascending:NO];
  104. list = [list sortedArrayUsingDescriptors:@[dsc]];
  105. for(NSInteger i = numberOfCacheFiles; i < list.count; ++i){
  106. XHFileAttribute *file = list[i];
  107. [[NSFileManager defaultManager] removeItemAtPath:file.filePath error:nil];
  108. }
  109. }
  110. - (void)_didAccessToDataForHash:(NSString *)hash {
  111. NSString *path = [self _pathForHash:hash];
  112. NSError *err = nil;
  113. NSFileManager *fileManager = [NSFileManager defaultManager];
  114. NSMutableDictionary *fileAttribute = [[fileManager attributesOfItemAtPath:path error:&err] mutableCopy];
  115. if(err) { return; }
  116. fileAttribute[NSFileModificationDate] = [NSDate date];
  117. [fileManager setAttributes:fileAttribute ofItemAtPath:path error:nil];
  118. }
  119. - (void)removeCacheForURL:(NSURL *)url {
  120. if(url.absoluteString.length>0){
  121. [self _removeCacheForHash:url.absoluteString.MD5Hash];
  122. }
  123. }
  124. - (void)_removeCacheForHash:(NSString *)hash {
  125. [_memoryCache removeObjectForKey:hash];
  126. [[NSFileManager defaultManager] removeItemAtPath:[self _pathForHash:hash] error:nil];
  127. }
  128. - (void)removeCacheDirectory {
  129. [_memoryCache removeAllObjects];
  130. [[NSFileManager defaultManager] removeItemAtPath:[self _cacheDirectory] error:nil];
  131. _cacheDirectoryPath = nil;
  132. }
  133. #pragma mark- NSData caching
  134. - (void)storeData:(NSData *)data forURL:(NSURL *)url storeMemoryCache:(BOOL)storeMemoryCache {
  135. if(data && url.absoluteString.length > 0){
  136. [self _storeData:data forHash:url.absoluteString.MD5Hash storeMemoryCache:storeMemoryCache];
  137. }
  138. }
  139. - (void)_storeData:(NSData *)data forHash:(NSString *)hash storeMemoryCache:(BOOL)storeMemoryCache {
  140. [self _didAccessToDataForHash:hash];
  141. if(storeMemoryCache) {
  142. [_memoryCache setObject:data forKey:hash];
  143. }
  144. [data writeToFile:[self _pathForHash:hash] atomically:NO];
  145. }
  146. - (NSData *)localCachedDataWithURL:(NSURL *)url {
  147. if(url.absoluteString.length > 0){
  148. return [self _localCachedDataWithHash:url.absoluteString.MD5Hash];
  149. }
  150. return nil;
  151. }
  152. - (NSData *)_localCachedDataWithHash:(NSString *)hash {
  153. [self _didAccessToDataForHash:hash];
  154. return [NSData dataWithContentsOfFile:[self _pathForHash:hash]];
  155. }
  156. - (NSData *)_cachedDataWithHash:(NSString *)hash storeMemoryCache:(BOOL)storeMemoryCache {
  157. NSData *data = [_memoryCache objectForKey:hash];
  158. if(data){
  159. [self _didAccessToDataForHash:hash];
  160. return data;
  161. }
  162. data = [self _localCachedDataWithHash:hash];
  163. if(storeMemoryCache && data!=nil){
  164. [_memoryCache setObject:data forKey:hash];
  165. }
  166. return data;
  167. }
  168. - (NSData *)dataWithURL:(NSURL *)url storeMemoryCache:(BOOL)storeMemoryCache {
  169. if(url.absoluteString.length == 0){
  170. return nil;
  171. }
  172. return [self _cachedDataWithHash:url.absoluteString.MD5Hash storeMemoryCache:storeMemoryCache];
  173. }
  174. - (BOOL)existsDataForURL:(NSURL *)url {
  175. if(url.absoluteString.length > 0){
  176. NSString *path = [self _pathForHash:url.absoluteString.MD5Hash];
  177. BOOL isDirectory = YES;
  178. BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory];
  179. return (exists && !isDirectory);
  180. }
  181. return NO;
  182. }
  183. #pragma mark- UIImage caching
  184. - (void)storeMemoryCacheWithImage:(UIImage *)image forURL:(NSURL *)url {
  185. if(image && url.absoluteString.length > 0){
  186. [self storeMemoryCacheWithImage:image forHash:url.absoluteString.MD5Hash];
  187. }
  188. }
  189. - (void)storeMemoryCacheWithImage:(UIImage *)image forHash:(NSString *)hash {
  190. [_memoryCache setObject:image forKey:hash];
  191. }
  192. - (UIImage *)imageWithURL:(NSURL *)url storeMemoryCache:(BOOL)storeMemoryCache {
  193. if(url.absoluteString.length == 0){
  194. return nil;
  195. }
  196. id data = [self dataWithURL:url storeMemoryCache:NO];
  197. if(data) {
  198. UIImage *image = nil;
  199. if([data isKindOfClass:[NSData class]]) {
  200. image = [UIImage fastImageWithData:data];
  201. }
  202. else if([data isKindOfClass:[UIImage class]]){
  203. image = (UIImage*)data;
  204. }
  205. if(image){
  206. if(storeMemoryCache){
  207. [self storeMemoryCacheWithImage:image forURL:url];
  208. }
  209. return image;
  210. }
  211. }
  212. return nil;
  213. }
  214. #pragma mark- wrapper
  215. + (void)limitNumberOfCacheFiles:(NSInteger)numberOfCacheFiles {
  216. [self.manager limitNumberOfCacheFiles:numberOfCacheFiles];
  217. }
  218. + (void)removeCacheForURL:(NSURL *)url {
  219. [self.manager removeCacheForURL:url];
  220. }
  221. + (void)removeCacheDirectory {
  222. [self.manager removeCacheDirectory];
  223. }
  224. + (void)storeData:(NSData *)data forURL:(NSURL *)url storeMemoryCache:(BOOL)storeMemoryCache {
  225. [self.manager storeData:data forURL:url storeMemoryCache:storeMemoryCache];
  226. }
  227. + (NSData *)localCachedDataWithURL:(NSURL *)url {
  228. return [self.manager localCachedDataWithURL:url];
  229. }
  230. + (NSData *)dataWithURL:(NSURL *)url storeMemoryCache:(BOOL)storeMemoryCache {
  231. return [self.manager dataWithURL:url storeMemoryCache:storeMemoryCache];
  232. }
  233. + (void)storeMemoryCacheWithImage:(UIImage*)image forURL:(NSURL*)url {
  234. [self.manager storeMemoryCacheWithImage:image forURL:url];
  235. }
  236. + (UIImage *)imageWithURL:(NSURL *)url storeMemoryCache:(BOOL)storeMemoryCache {
  237. return [self.manager imageWithURL:url storeMemoryCache:storeMemoryCache];
  238. }
  239. + (BOOL)existsDataForURL:(NSURL *)url {
  240. return [self.manager existsDataForURL:url];
  241. }
  242. @end