本文部分内容摘录自:人魔七七:http://www.cnblogs.com/qiqibo/
缓存分为两种:1:按需缓存,2:预缓存。
第一种是**按需缓存**,这种情况下应用缓存起请求应答,就和Web浏览器的工作原理一样;按需缓存工作原理类似于浏览器缓存。它允许我们查看以前查看或者访问过的内容。按需缓存可以通过在打开一个视图控制器时按需地缓存数据模型(创建一个数据模型缓存)来实现,而不是在一个后台线程上做这件事。
第二种是**预缓存**,这种情况是缓存全部内容(或者最近n条记录)以便离线访问。例如:网易新闻的离线阅读
在众多可以本地保存数据的技术中,有三种脱颖而出:URL缓存、数据模型缓存(利用NSKeyedArchiver)和Core Data。
假设你正在开发一个应用,需要缓存数据以改善应用表现出的性能,你应该实现按需缓存(使用数据模型缓存或URL缓存)。另一方面,如果需要数据能够离线访问,而且具有合理的存储方式以便离线编辑,那么就用高级序列化技术(如Core Data)。
URL缓存、数据模型缓存(利用NSKeyedArchiver)适用于 -- 按需缓存
Core Data或者SQLite 适用于 -- 预缓存
---------以下为编者自己的见解----------------
两种缓存的实现方式:
按需缓存: a:可以通过对URL地址编码,设计一个单例,这个单例中管理着一个字典,字典格式为dic={[url md5]:"过期日期"},每次请求都将请求的NSData数据保存到沙盒目录,下次请求时,先去字典中查找是否有此键值,有的话,在判断是否已经过期,如果过期再去请求。b:方式是一样的,只是不使用单例,而是直接使用数据库,存储的信息也是字典中的那种格式。
按需缓存有两个优点:1:缓解服务器压力,2:节省用户流量。当然它的缺点就是不能及时的让用户获取及时的信息。当然你可以通过设置过期日期来缓解。
预缓存:可以将每次请求下得NSData,解析成模型数组后,将每个模型保存到数组库中。每次View加载ViewDidLoad方法中先从数据库中读取数据,在ViewWillApperence 中请求数据。预缓存就是用来实现离线缓存的。通常我们所说的缓存就是离线缓存,但是根据需要可以两种方式结合使用。
代码:
第一种:按需缓存
// // AZCacheSignal.h // AZSMZDM // // Created by AndrewZhang on 14-12-19. // Copyright (c) 2014年 AndrewZhang. All rights reserved. // #import <Foundation/Foundation.h> #import "NSString+Hashing.h" @interface AZCacheSignal : NSObject @property (nonatomic,assign)NSUInteger cacheSize; #pragma mark -- 对外接口 +(instancetype)defaultCache; #pragma mark -- 使用 Url + NSData的缓存方式 /** Url缓存,第一个参数:url地址,第二个参数:多少秒过期 */ -(void)setCacheUrlStr:(NSString *)string andTimeOut:(NSTimeInterval)time andData:(NSData *)data; /** 得到缓存字典,外界将请求地址url经过MD5编码,然后遍历这个字典。看是否找到有这个键,如有没有,则访问url,如果有,则判断当前系统时间是否已经超过了过期时间,如果超过了,则请求url,如果咩有超过,则不请求,直接从 取出NSData。 */ -(NSDictionary *)getCacheDic; @end
// // AZCacheSignal.m // AZSMZDM // // Created by AndrewZhang on 14-12-19. // Copyright (c) 2014年 AndrewZhang. All rights reserved. // #import "AZCacheSignal.h" @interface AZCacheSignal() @property (nonatomic,strong)NSString *path; @property (nonatomic,strong)NSString *dataPath; @end @implementation AZCacheSignal -(instancetype)init { if (self=[super init]) { self.cacheSize=0; } return self; } -(void)setCacheSize:(NSUInteger)cacheSize { _cacheSize=_cacheSize+cacheSize; } +(instancetype)defaultCache { static AZCacheSignal *_cache=nil; @synchronized(self)//线程安全 { if (!_cache) { _cache=[[AZCacheSignal alloc] init]; } } return _cache; } #pragma mark -- 可以在此处修改缓存字典保存的沙盒路径 -(NSString *)path { if (!_path) { _path=[NSString stringWithFormat:@"%@/Library/Caches/AZMyAppCacheDic.plist",NSHomeDirectory()]; } return _path; } #pragma mark --可以在此处修改 NSData 保存的沙盒路径 /** Url缓存,第一个参数:url地址,第二个参数:多少秒过期 设计字典 dic={“urlMD5加密”:“过期时间”}; 保存字典到沙盒目录中的 Library/Caches/AZMyAppCacheDic.plist 保存NSData到沙盒目录中的 tmp/ */ -(void)setCacheUrlStr:(NSString *)string andTimeOut:(NSTimeInterval)time andData:(NSData *)data; { NSDate *passDate=[NSDate dateWithTimeInterval:time sinceDate:[NSDate date]]; NSFileManager* fm=[NSFileManager defaultManager]; if (![fm fileExistsAtPath:self.path]) { NSDictionary *dic=[NSDictionary dictionary]; [dic writeToFile:self.path atomically:YES]; } NSDictionary *cacheDic=[NSDictionary dictionaryWithContentsOfFile:self.path]; [cacheDic setValue:passDate forKey:[string MD5Hash]]; [cacheDic writeToFile:self.path atomically:YES]; NSString* dataPath=[NSString stringWithFormat:@"%@/tmp/%@",NSHomeDirectory(),[string MD5Hash]]; [data writeToFile:dataPath atomically:NO]; } /** 得到缓存字典 */ -(NSDictionary *)getCacheDic { NSFileManager* fm=[NSFileManager defaultManager]; if (![fm fileExistsAtPath:self.path]) { NSDictionary *dic=[NSDictionary dictionary]; [dic writeToFile:self.path atomically:YES]; } return [NSDictionary dictionaryWithContentsOfFile:self.path]; } @end
预缓存使用数据库,推荐使用CoreData,但是这里因为我已经建好了数据模型,所以使用了FMDB。
#import <Foundation/Foundation.h> #import "FMDatabase.h" @interface AZDataBase : NSObject @property (nonatomic,strong)FMDatabase * db; +(instancetype)shareDataBase; //根据数组插入数据到数据库 -(void)insertShowItemByArray:(NSArray *)array andPage:(NSString *)page; -(void)insertLunFanItemByArray:(NSArray *)array; //删除page指定的所有数据 -(void)delShowItemByPage:(NSString *)page; //全部删除轮番数据 -(void)delLunFan; //查询数据 -(NSArray *)selectShowItemByPage:(NSString *)page; -(NSArray *)selectLunFan; @end
// // AZDataBase.m // AZSMZDM // // Created by AndrewZhang on 14-12-25. // Copyright (c) 2014年 AndrewZhang. All rights reserved. // #import "AZDataBase.h" #import "AZShowItem.h" #import "AZLunFanModel.h" @implementation AZDataBase -(FMDatabase *)db { if (!_db) { NSString *path=[NSString stringWithFormat:@"%@/Documents/data.db",NSHomeDirectory()]; //数据库操作类 _db=[[FMDatabase alloc] initWithPath:path]; BOOL res=[_db open]; if (!res) { NSLog(@"数据库打开失败"); } else { //创建表 res=[_db executeUpdate:@"create table if not exists ShowItem(uid integer primary key autoincrement,article_channel_id,article_channel_name,article_id,article_url,article_title,article_price,article_format_date,article_link,article_link_type,article_pic,article_worthy,article_unworthy,article_collection,article_comment,article_mall,article_referrals,article_rzlx,article_filter_content,page)"]; if (!res) { NSLog(@"创建表1失败"); } res=[_db executeUpdate:@"create table if not exists LunFan(uid integer primary key autoincrement,banner_id,article_channel_id,article_id,banner_title,banner_pic,banner_url,banner_order,banner_type)"]; if (!res) { NSLog(@"创建表2失败"); } } [_db close]; } return _db; } +(instancetype)shareDataBase { static AZDataBase *_database=nil; @synchronized(self)//线程安全 { if (!_database) { _database=[[AZDataBase alloc] init]; } } return _database; } //根据数组插入数据到数据库 -(void)insertShowItemByArray:(NSArray *)array andPage:(NSString *)page { [self.db open]; for (AZShowItem *showItem in array) { [self.db executeUpdate:@"insert into ShowItem(article_channel_id,article_channel_name,article_id,article_url,article_title,article_price,article_format_date,article_link,article_link_type,article_pic,article_worthy,article_unworthy,article_collection,article_comment,article_mall,article_referrals,article_rzlx,article_filter_content,page)values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",showItem.article_channel_id,showItem.article_channel_name,showItem.article_id,showItem.article_url,showItem.article_title,showItem.article_price,showItem.article_format_date,showItem.article_link,showItem.article_link_type,showItem.article_pic,showItem.article_worthy,showItem.article_unworthy,showItem.article_collection,showItem.article_comment,showItem.article_mall,showItem.article_referrals,showItem.article_rzlx,showItem.article_filter_content,page]; } [self.db close]; } -(void)insertLunFanItemByArray:(NSArray *)array { [self.db open]; for (AZLunFanModel *lf in array) { [self.db executeUpdate:@"insert into LunFan(banner_id,article_channel_id,article_id,banner_title,banner_pic,banner_url,banner_order,banner_type)values(?,?,?,?,?,?,?,?)",lf.banner_id,lf.article_channel_id,lf.article_id,lf.banner_title,lf.banner_pic,lf.banner_url,lf.banner_order,lf.banner_type]; } [self.db close]; } //删除page指定的所有数据 -(void)delShowItemByPage:(NSString *)page { [self.db open]; NSString *delStr=[NSString stringWithFormat:@"delete from ShowItem WHERE page='%@' ",page]; [self.db executeUpdate:delStr]; [self.db close]; } //全部删除轮番数据 -(void)delLunFan { [self.db open]; NSString *delStr=[NSString stringWithFormat:@"delete from LunFan"]; [self.db executeUpdate:delStr]; [self.db close]; } //查询数据 -(NSArray *)selectShowItemByPage:(NSString *)page { [self.db open]; NSString *selectStr=[NSString stringWithFormat:@"select * from ShowItem where page='%@' ",page]; FMResultSet *resultSet=[self.db executeQuery:selectStr]; NSMutableArray *temArray=[NSMutableArray array]; if (resultSet) { // 遍历结果集 while ([resultSet next]) { AZShowItem *showItem=[[AZShowItem alloc] init]; showItem.article_channel_id=[resultSet stringForColumn:@"article_channel_id"]; showItem.article_channel_name=[resultSet stringForColumn:@"article_channel_name"]; showItem.article_id=[resultSet stringForColumn:@"article_id"]; showItem.article_url=[resultSet stringForColumn:@"article_url"]; showItem.article_title=[resultSet stringForColumn:@"article_title"]; showItem.article_price=[resultSet stringForColumn:@"article_price"]; showItem.article_format_date=[resultSet stringForColumn:@"article_format_date"]; showItem.article_link=[resultSet stringForColumn:@"article_link"]; showItem.article_link_type=[resultSet stringForColumn:@"article_link_type"]; showItem.article_pic=[resultSet stringForColumn:@"article_pic"]; showItem.article_worthy=[resultSet stringForColumn:@"article_worthy"]; showItem.article_unworthy=[resultSet stringForColumn:@"article_unworthy"]; showItem.article_collection=[resultSet stringForColumn:@"article_collection"]; showItem.article_comment=[resultSet stringForColumn:@"article_comment"]; showItem.article_mall=[resultSet stringForColumn:@"article_mall"]; showItem.article_referrals=[resultSet stringForColumn:@"article_referrals"]; showItem.article_rzlx=[resultSet stringForColumn:@"article_rzlx"]; showItem.article_filter_content=[resultSet stringForColumn:@"article_filter_content"]; [temArray addObject:showItem]; } } [self.db close]; return [temArray copy]; } -(NSArray *)selectLunFan { [self.db open]; NSString *selectStr=[NSString stringWithFormat:@"select * from LunFan"]; FMResultSet *resultSet=[self.db executeQuery:selectStr]; NSMutableArray *temArray=[NSMutableArray array]; if (resultSet) { // 遍历结果集 while ([resultSet next]) { AZLunFanModel *lf=[[AZLunFanModel alloc] init]; lf.banner_id=[resultSet stringForColumn:@"banner_id"]; lf.article_channel_id=[resultSet stringForColumn:@"article_channel_id"]; lf.article_id=[resultSet stringForColumn:@"article_id"]; lf.banner_title=[resultSet stringForColumn:@"banner_title"]; lf.banner_pic=[resultSet stringForColumn:@"banner_pic"]; lf.banner_url=[resultSet stringForColumn:@"banner_url"]; lf.banner_order=[resultSet stringForColumn:@"banner_order"]; lf.banner_type=[resultSet stringForColumn:@"banner_type"]; [temArray addObject:lf]; } } [self.db close]; return [temArray copy]; } @end
图:
在离线下: