iOS如何实现图片缓存
在很多情况下,我们的项目中都会集成SDWebImage,但是由于版本问题,可能会造成各种的冲突。(比如集成了环信的demo,使用了比较旧的SDWebImage版本,但是自己的项目集成使用了4.0以上的版本,最要命的是使用cocoapods集成,这种冲突很难解决,版本不兼容pod install执行不过)
在这里我以集成环信Demo为例,介绍一下我自己实现的一个轻量级ImageCache框架。
环信的easeui依赖下面三个依赖,MWPhotoBrowser又依赖了SDWebImage,MBProgressHUD,DACircularProgress
spec.dependency 'MWPhotoBrowser', '~> 2.1.1' spec.dependency 'MJRefresh', '~> 3.1.0' spec.dependency 'Hyphenate', '~> 3.3.4'
我自己的项目也用到了SDWebImage,而且我又想用到环信IM功能。但是这个冲突很难解决,需要改很多代码。其实我只用到了SDWebImage中很少的功能,最多就是gif,imageview可以加载网络图片。自己实现一个imagecache也不是一件很难的事情。
--------------------------------------------------------------------
我自己实现的图片缓存分为3个模块,网络下载,任务调度,数据缓存。
首先我自己实现了一个很简单的网络下载功能,可以下载网络图片,项目地址(https://github.com/lizilong1989/LongRequest.git)
其次我自己实现了一个很简单的任务调度功能,基于GCD实现,可以限制线程的并发,取消任务等功能,项目地址(https://github.com/lizilong1989/LongDispatch.git)
下面是我说的重点,imagecache的实现。主要原理就是LRU缓存算法,为了提供访问的效率,我实现了两个集合结构(数组和字典)。数组主要负责存储key,而字典是存储数据,LRU缓存淘汰算法主要操作的是数组,数据淘汰时同时会把字典中的数据删除。
存储数据:
- (void)storeCacheWithData:(NSData *)aData forKey:(NSString*)aKey toDisk:(BOOL)aToDisk { if (![aData isKindOfClass:[NSData class]] || ![aKey isKindOfClass:[NSString class]]) { return; } if (aData.length == 0 || aKey.length == 0) { return; } pthread_mutex_lock(&_mutex); NSString *md5Key = [aKey md5String]; if (CFDictionaryContainsKey(_dicRef, (__bridge const void *)aKey)) { [self _removeWithKey:md5Key]; CFArrayInsertValueAtIndex(_arrayRef, 0, (__bridge const void *)aKey); CFDictionarySetValue(_dicRef, (__bridge const void *)aKey, CFDataCreate(0, aData.bytes, aData.length)); } else { CFIndex count = CFArrayGetCount(_arrayRef); if (count >= kDefaultMaxCacheSize) { const void *key = CFArrayGetValueAtIndex(_arrayRef, count - 1); CFArrayRemoveValueAtIndex(_arrayRef, count - 1); CFDictionaryRemoveValue(_dicRef, key); } CFArrayInsertValueAtIndex(_arrayRef, 0, (__bridge const void *)aKey); CFDictionarySetValue(_dicRef, (__bridge const void *)aKey,CFDataCreate(0, aData.bytes, aData.length)); } if (aToDisk) { [self _saveCacheFromDiskWithData:aData forKey:md5Key]; } pthread_mutex_unlock(&_mutex); }
获取数据:
- (NSData*)getCacheWithKey:(NSString*)aKey { NSData *obj = nil; if (![aKey isKindOfClass:[NSString class]] || aKey.length == 0) { return obj; } pthread_mutex_lock(&_mutex); NSString *md5Key = [aKey md5String]; if (CFDictionaryContainsKey(_dicRef, (__bridge const void *)aKey)) { obj = (__bridge NSData*)CFDictionaryGetValue(_dicRef, (__bridge const void *)aKey); } if (!obj) { obj = [self _getCacheFromDiskWithKey:md5Key]; } pthread_mutex_unlock(&_mutex); return obj; }
imagecache同时也支持播放gif,显示webp格式图片和简单的图片浏览等功能。
--------------------------------------------------------------------
集成Imagecache也非常简单,支持cocoapods集成
pod 'LongImageCache'
图片缓存使用方法
//首先引入header #import "UIImageView+LongCache.h" //缓存图片 NSString *url = @"http://127.0.0.1/test.jpg"; [imageView setImageWithUrl:url placeholderImage:nil toDisk:YES];
imagecache项目地址:https://github.com/lizilong1989/LongImageCache
依赖LongImageCache的easeui地址:https://github.com/lizilong1989/easeui-ios-hyphenate-cocoapods/tree/3party_easeui
对应的环信Demo地址:https://github.com/lizilong1989/sdkdemoapp3.0_ios/tree/3rdparty_sdk3.x