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

posted @ 2017-10-25 12:48  shuffle  阅读(1766)  评论(0编辑  收藏  举报