iOS-- 缓存

本文部分内容摘录自:人魔七七: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

预缓存的主要目的 就是在离线的情况下 打开应用程序不会出现空白一片。而是显示的缓存中的数据。这样可以提高用户体验。


图:

在离线下:

iOS-- 缓存_第1张图片   




你可能感兴趣的:(iOS-- 缓存)