socket协议下如何缓存图片--推荐EGOCache
EGOCache是一个轻量级的缓存框架。用法简单方便,在现在的项目中,我就用到EGOCache来缓存下载过的照片和字符串。
有人可能会问到,缓存照片还需要用EGOCache吗?AFNetworking和SDWebImage不是已经有这些功能了吗?
是的,不过AFNetworking和SDWebImage是http。我的项目用的是socket,所以我选择EGOCache来做缓存。用下来觉得EGOCache还是挺强大的。
EGOCache简介
EGOCache is a simple, thread-safe key value cache store. It has native support for NSString, UI/NSImage, and NSData, but can store anything that implements <NSCoding>. All cached items expire after the timeout, which by default, is one day.
翻译过来就是:EGOCache一个简单、线程安全的基于 key-value 的缓存框架,原生支持NSString、UI/NSImage、和NSData,也支持储存任何实现协议的类,可以设定缓存过期时间,默认是1天。
EGOCache只有一个类,EGOCache.h和EGOCache.m两个文件。用法也比较容易掌握,仔细研究一下EGOCache.h的方法,很快就可以上手。
EGOCache只提供了磁盘缓存,没有提供内存缓存。同时,也提供了清理缓存的方法:
- (void)clearCache;
EGOCache还提供了判断缓存是否存在的方法:
- (BOOL)hasCacheForKey:(NSString* __nonnull)key;
通过Cocoapods直接加入项目
直接在你的项目的Podfile加入下面一行:
pod 'EGOCache'
然后执行:
$ pod update
EGOCache用法
用EGOCache缓存NSString
存储:
NSString *saveString = @"把我保存起来吧";
[[EGOCache globalCache] setString:saveString forKey:[NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[saveString hash]] withTimeoutInterval:24*60*60];
读取:
NSString *getSaveString = [[EGOCache globalCache] stringForKey:[NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[@"SaveString" hash]]];
是不是感觉跟NSDictionary很相似,确实,前面我们说了EGOCache是基于key-value 的缓存框架。
用EGOCache缓存UIImage
存储:
UIImage *saveImage = [UIImage imageNamed:@"iOSDevTip"];
[[EGOCache globalCache] setImage:saveImage forKey:[NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[@"SaveImage" hash]] withTimeoutInterval:24*60*60];
读取:
UIImage *getSaveImage = [[EGOCache globalCache] imageForKey:[NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[@"SaveImage" hash]]];
用EGOCache缓存NSData
存储:
NSData *saveData = [NSData data];
[[EGOCache globalCache] setData:saveData forKey:[NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[@"SaveData" hash]] withTimeoutInterval:24*60*60];
读取:
UIImage *getSaveData = [[EGOCache globalCache] dataForKey:[NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[@"SaveData" hash]]];
EGOCache源码下载
EGOCache : https://github.com/enormego/EGOCache
EGOCache可以设定缓存过期时间,默认是1天。查看了一下EGOCache源码,设置默认时间:
[self setDefaultTimeoutInterval:86400];
//86400 = 24 * 60 * 60 刚好是一天时间。
EGOCache为什么要提供设定缓存过期时间呢?或者说设定缓存过期时间有什么好处呢?我觉得最大的好处就是可以定时清除缓存。可以设置某一项的缓存时间,很方便管理缓存。
那么问题来了:
EGOCache是怎么检测缓存过期时间的呢?
检测到时间过期之后,什么时候触发删除缓存项的?
带着这两个问题,我们来继续分析。
你会怎么实现
记得在公司里,老板经常会举这样的例子:
某某同志,刚来我们公司的时候,遇到问题就知道抱怨。从来不知道去思考怎么解决,只知道把问题抛给领导。工作半年下来,成长了很多。现在碰到问题,不仅把问题抛出来,而且还提供了自己的解决方案...
类似的例子,相信大家都听过。同样,既然前面我们提出这两个问题,我们也先来思考一下,如果我们来做该怎么解决?
如果让我来写的话,我脑海里初步实现方法有几个:
通过定时器来轮询,每隔一段时间检测一次。
写一个while循环来检测。
每次去读取缓存项的时候,判断缓存时间有没有过期。没过期,就返回读取的缓存项;否则,返回nil。
当然,还有一些方法,不一一例举了。仔细想想,这些方法弊端很容易显露出来。
为了小小的缓存时间,就用定时器轮询,显然是资源浪费
跟方法1差不多。
每次读取的时候判断是否过期,如果一直不读取,app的缓存会越来越大,也不可取。
这些方法都被排除了,还有好的方法吗?继续往下看:
EGOCache是怎么实现的?
仔细查看EGOCache源码,发现在initWithCacheDirectory:方法里,每次初始化EGOCache实例对象的时,会遍历一遍plist文件中所有已存在的缓存项,拿每个缓存项的时间和当前时间作比较,缓存项过期时间早于当前时间,则删除对应缓存文件,并删除 plist 文件中对应 key 的记录。
具体实现代码如下:
读取缓存项信息
_cacheInfo = [[NSDictionary dictionaryWithContentsOfFile:cachePathForKey(_directory, @"EGOCache.plist")] mutableCopy];
if(!_cacheInfo) {
_cacheInfo = [[NSMutableDictionary alloc] init];
}
获取当前时间的NSTimeInterval
NSTimeInterval now = [[NSDate date] timeIntervalSinceReferenceDate];
声明removedKeys保存过期的缓存项对应的key
NSMutableArray* removedKeys = [[NSMutableArray alloc] init];
遍历缓存项信息并判断缓存时间
for(NSString* key in _cacheInfo) {
//判断缓存项过期时间是否早于当前时间
if([_cacheInfo[key] timeIntervalSinceReferenceDate] <= now) {
//如果缓存项过期时间早于当前时间,移除缓存项
[[NSFileManager defaultManager] removeItemAtPath:cachePathForKey(_directory, key) error:NULL];
//把过期的缓存项对于的key保存到removedKeys里面
[removedKeys addObject:key];
}
}
删除过期缓存项对于的key
[_cacheInfo removeObjectsForKeys:removedKeys];
看到这些,是不是觉得人家思路特牛叉,反正,我是觉得这个作者不简单。到这一步就解决了吗?
EGOCache还做了什么?
细心的童鞋会发现:EGOCache是个单列类,也就是说整个程序应用周期只初始化一次。
+ (instancetype)globalCache {
static id instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[[self class] alloc] init];
});
return instance;
}
每次初始化的时候去判断了缓存项是否过期,这样做非常正确。思考一个场景:
用户打开app,EGOCache被初始化,并判断了缓存项是否过期。
如果刚好有一些缓存项在EGOCache被初始化之后过期。这个时候我们依然可以读到这个缓存项。这就不对了。
继续分析EGOCache源码发现,EGOCache在读取一个缓存项的时候,先判断缓存项是否存在,然后读取缓存项(注意:是读取EGOCache初始化的时候没有过期的缓存项,并没有说现在没有过期),最后去判断读取到的缓存项跟当前时间相比是否过期.
具体实现如下:
- (BOOL)hasCacheForKey:(NSString*)key {
//读取EGOCache初始化的时候没有过期的缓存项
NSDate* date = [self dateForKey:key];
if(date == nil) return NO;
//判断读取到的缓存项当前是否过期
if([date timeIntervalSinceReferenceDate] < CFAbsoluteTimeGetCurrent()) return NO;
return [[NSFileManager defaultManager] fileExistsAtPath:cachePathForKey(_directory, key)];
}
- (NSDate*)dateForKey:(NSString*)key {
__block NSDate* date = nil;
dispatch_sync(_frozenCacheInfoQueue, ^{
date = (self.frozenCacheInfo)[key];
});
return date;
}
EGOCache检测缓存时间过期的思路值得学习,以后遇到类似场景,完全可以借鉴。
socket协议下如何缓存图片--推荐EGOCache的更多相关文章
- document.execCommand("BackgroundImageCache",false,true)解决ie6下的背景图片缓存问题
E6下的背景图片每次使用都会重新发送请求(not 本地),连一个hover效果时候同样的背景图片仅仅位置不同而已,ie6都会再次发送请求,这个令人崩溃的事情需要解决掉:对于ie来说,filter:ex ...
- tcp协议下的Socket
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net ...
- .Net环境下的缓存技术介绍 (转)
.Net环境下的缓存技术介绍 (转) 摘要:介绍缓存的基本概念和常用的缓存技术,给出了各种技术的实现机制的简单介绍和适用范围说明,以及设计缓存方案应该考虑的问题(共17页) 1 概念 ...
- .Net环境下的缓存技术介绍
.Net环境下的缓存技术介绍 摘要: 介绍缓存的基本概念和常用的缓存技术,给出了各种技术的实现机制的简单介绍和适用范围说明,以及设计缓存方案应该考虑的问题(共17页) 1 概念 1.1 ...
- Linux 下 Memcached 缓存服务器安装配置
Linux 下 Memcached 缓存服务器安装配置 [日期:2011-08-06] 来源:Linux社区 作者:Linux [字体:大 中 小] [安装Memcache服务器端]我目前的平台 ...
- Android中高效的显示图片之三——缓存图片
加载一张图片到UI相对比较简单,如果一次要加载一组图片,就会变得麻烦很多.像ListView,GridView,ViewPager等控件,需要显示的图片和将要显示的图片数量可能会很大. 为了减少内存使 ...
- Android-Universal-Image-Loader的缓存处理机制与使用 LruCache 缓存图片
讲到缓存,平时流水线上的码农一定觉得这是一个高大上的东西.看过网上各种讲缓存原理的文章,总感觉那些文章讲的就是玩具,能用吗?这次我将带你一起看过UIL这个国内外大牛都追捧的图片缓存类库的缓存处理机制. ...
- Android下的缓存策略
Android下的缓存策略 内存缓存 常用的内存缓存是软引用和弱引用,大部分的使用方式是Android提供的LRUCache缓存策略,本质是个LinkedHashMap(会根据使用次数进行排序) 磁盘 ...
- Android之简单了解Bitmap显示图片及缓存图片
昨天我们学了如何连接网络,今天我们就学习一下如何从把网上图片显示到项目中 今天主要用到的是Bitmap 类 Bitmap是Android系统中的图像处理的最重要类之一.用它可以获取图像文件信息,进行图 ...
随机推荐
- cargo failed to finish deploying within the timeout period [120000]
cargo插件,报错:failed to finish deploying within the timeout period [120000] 解决方法:配置timeout为0 <plugin ...
- 初识Python第二天(1)
在Python中,一切事物都是对象,对象是基于类创建的,对象继承了类的属性,方法等. 一.传递参数 1.1新建python文件,名为twoday_args.py,输出以下代码 import sys p ...
- GAT2.0使用文档(组合接口测试)
3.2接口用例场景组件 在此之前,大家应该都已经开发完成了一个最简单的接口测试用例,但是之前的接口用例的期望结果是固定值,不能动态的去做对比,有很大局限性.下面开始介绍怎样通过场景组件来动态对测试结果 ...
- python:HTML + CSS 优先级 返回顶部
优先级 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...
- ucenter的单点登录
所谓单点登录,无非就是几个站点共用一个用户中心,实现同步登陆,同步退出. 服务器端:Loog SSO . 客服端: ucenter,说实话dz商业化确实让php发展了不少. ucenter 基本原理: ...
- hadoop2.0初识1.2
1 hadoop启动方式(三种) 1.1 各个服务组件逐一启动 *dfs hadoop-daemon.sh start|stop namenode|datanode|secondarynamenode ...
- VS2010/2012配置优化记录笔记
VS2010/2012配置优化记录笔记 在某些情况下VS2010/2012运行真的实在是太卡了,有什么办法可以提高速度吗?下面介绍几个优化策略,感兴趣的朋友可以参考下,希望可以帮助到你 有的时候V ...
- 解决GitLab提交MergeRequest时,提示502 GitLab is not responding.的问题
最近使用GitLab提交MergeRequest时,提示502 GitLab is not responding. 使用gitlab-ctl tail查看错误信息如下: 2014/10/28 11:5 ...
- mysql 日期格式化
SELECT plc.id, plc.policy_no, plc.out_date, og.organ_name, ir.insurer_name, pd.product_name, plc.pol ...
- python成长之路【第七篇】:面向对象
概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 面向对象三大特性 面向 ...