iOS数据持久化

今天想来聊聊iOS的数据持久化。因为今天在家辅导表弟,玩iPad的时候,发现XX应用没有对首页做缓存,正好家里网断了(初三小表弟,你懂得),手机共享伤不起。

回归正题,我建议凡是数据比较多的应用,你都要考虑做下缓存,我看今日头条就不错,在网好的时候,它除了新闻的图片不提前缓存,所有首页文字信息都提前缓存下来了,看的很舒服。
iOS数据持久化,无非几种。

分开讲吧,这篇讲,归档吧。(Archiver持久化)

我推荐一个关于Archive的博文,很详细,这里就不多做说明了。点击打开链接

基本的数据类型如NSString、NSDictionary、NSArray、NSData、NSNumber等可以用属性列表的方法持久化到.plist 文件中,但如果是一些自定义的类的话,属性列表的方法就不管用了。archiver 方法可以做到。

这里强调下,NSKeyedArchive 并不是所有对象都可以通过它来归档的,我们想要归档的话,就必须要遵守NSCoding协议

遵守协议是第一步,之后在遵守协议,希望归档的对象实现两个协议方法,就可以实现数据归档了。

一、 encodeWithCoder:(NSCoder *)encoder  代理方法

-(void)encodeWithCoder:(NSCoder *)encoder{  

[super encodeWithCoder:encoder];//不要忘了这个  首先要调用父类的方法,NSObject除外,NSObject 没有实现此方法。

[encoder encodeInt:self.age forKey:@"age"]; 

[encoder encodeObject:self.name forKey:@"name"];  

[encoder encodeFloat:self.height forKey:@"height"];  


二、initWithCoder:(NSCoder *)decoder  代理方法

-(id)initWithCoder:(NSCoder *)decoder{   

self = [super initWithCoder:decoder];//不要忘了这个  

self.age = [decoder decodeIntForKey:@"age"];

self.name = [decoder decodeObjectForKey:@"name"];   

self.height = [decoder decodeFloatForKey:@"height"];

 return self;  

}


之后的操作就是在归档的地方归档在想解档的地方解档

    //创建  
    -(void)createPerson{  
          
        person *p = [[[person alloc] init] autorelease];  
        p.age = 20;  
        p.name = @"Rio";  
        p.height =1.75f;  
          
        //获得Document的路径  
        NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];  
        NSString *path = [documents stringByAppendingPathComponent:@"person.archiver"];//拓展名可以自己随便取  
          
        [NSKeyedArchiver archiveRootObject:p toFile:path];  
          
    }  
      
    //读取  
    -(void)readPerson{  
        NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];  
        NSString *path = [documents stringByAppendingPathComponent:@"person.archiver"];  
        person *person1 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];  
        NSLog(@"%@",person1);  
    }  

之后,我之前做一款应用时,就用到过这方面来处理缓存

把原理和源码也放在这里了,

原理就是归档,通过请求数据的URL来命名归档的文件名,加上MD5加密一下,基本保证了文件名不重复,

MD5 加密如下,我的处理是给NSString加上了一个类别。


//
//  ScienceCacheManager.m
//  每日新鲜事
//
//  Created by JackYang on 15/9/1.
//  Copyright (c) 2015年 JackYang. All rights reserved.
//

#import "NSString+Hashing.h"
#import <CommonCrypto/CommonDigest.h>

@implementation NSString (NSString_Hashing)

- (NSString *)MD5Hash
{
    const char *cStr = [self UTF8String];
    unsigned char result[16];
    CC_MD5(cStr, strlen(cStr), result);
    return [NSString stringWithFormat:
            @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
            result[0], result[1], result[2], result[3],
            result[4], result[5], result[6], result[7],
            result[8], result[9], result[10], result[11],
            result[12], result[13], result[14], result[15]];
}

@end



剩下的代码就比较通用了。

我都放在这里了。


//
//  LimitCachManager.h
//  每日新鲜事
//
//  Created by JackYang on 15/9/16.
//  Copyright (c) 2015年 JackYang. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface LimitCachManager : NSObject

//保存url 对应的数据
+ (void)saveData:(id)object atUrl:(NSString*)url;

//读取url对应的数据
+ (id)readDataAtUrl:(NSString*)ulr;

//判断缓存数据是否有效
+ (BOOL)isCacheDataInvalid:(NSString*)url;

//计算缓存的大小
+ (NSInteger)cacheSize;

//清除缓存
+ (void)clearDisk;


@end

主要实现

#import "LimitCachManager.h"
#import "NSString+Hashing.h"

@implementation LimitCachManager

//得到本地缓存的目录
+ (NSString*)cacheDirectory
{
    //得到沙盒目录下的cache文件夹
    NSString *cachDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    cachDir = [cachDir stringByAppendingPathComponent:@"LimitCache"];
    //创建LimitCache文件夹,目的是把所有的缓存数据放到该文件夹下面
    //attribute:nil只文件夹跟父文件夹一样的读写属性
    NSError *error;
    BOOL bret = [[NSFileManager defaultManager] createDirectoryAtPath:cachDir withIntermediateDirectories:YES attributes:nil error:&error];
    if (!bret) {
        NSLog(@"%@",error);
        return nil;
    }

    return cachDir;
}


+ (NSString*)cacheFileFullPath:(NSString*)url
{
    //得到保存的文件的全路径,使用url的MD5加密得到的字符串作为文件名
    //这样url和文件名就对应起来了
    //[url MD5Hash] 是把url进行MD5加密得到的字符串
    //MD5 加密算法是不可逆的
    NSString *fileName = [url MD5Hash];
    NSString *cacheDir = [self cacheDirectory];
    return [cacheDir stringByAppendingPathComponent:fileName];
}

//保存url 对应的数据
//输入的数据,要么是字典,要么数组
+ (void)saveData:(id)object atUrl:(NSString*)url{
    //首先得到保存的文件路径
    NSString *fileFullPath = [self cacheFileFullPath:url];

    //写入数据,使用NSKeyedArchiver进行数据转换
    NSData *data = [NSKeyedArchiver  archivedDataWithRootObject:object];
    [data writeToFile:fileFullPath atomically:YES];
}

//读取url对应的数据
+ (id)readDataAtUrl:(NSString*)url
{
    NSString *fileFullPath = [self cacheFileFullPath:url];
    NSData *data = [NSData dataWithContentsOfFile:fileFullPath];
    return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}

//判断缓存数据是否有效
+ (BOOL)isCacheDataInvalid:(NSString*)url
{
    //isDirectory 的参数是返回给我们是否是一个目录
    NSString *fileFullPath = [self cacheFileFullPath:url];
    BOOL isFileExist = [[NSFileManager defaultManager] fileExistsAtPath:fileFullPath isDirectory:nil];
    //获取文件的属性
    NSDictionary *attributeDic = [[NSFileManager defaultManager] attributesOfItemAtPath:fileFullPath error:nil];
    NSDate *lastModify = attributeDic.fileModificationDate;
    NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:lastModify];
    BOOL isExpire = (timeInterval > 60*60);
    if (isFileExist && !isExpire) {
        return YES;
    }
    return NO;
}



//计算缓存的大小,遍历缓存目录,把文件内容大小累加
+ (NSInteger)cacheSize
{
    NSInteger totalSize = 0;
    NSString *cacheDir = [self cacheDirectory];
    //得到目录的枚举器,使用它来枚举目录下的所有文件
    NSDirectoryEnumerator *enmuerator = [[NSFileManager defaultManager]enumeratorAtPath:cacheDir];
    for (NSString *fileName in enmuerator) {
        NSString *fileFullPath = [cacheDir stringByAppendingPathComponent:fileName];
        NSDictionary *attributeDic = [[NSFileManager defaultManager] attributesOfItemAtPath:fileFullPath error:nil];
        totalSize += attributeDic.fileSize;
    }
    return totalSize;
}

//清除缓存
+ (void)clearDisk
{
    NSString *cacheDir = [self cacheDirectory];
    [[NSFileManager defaultManager] removeItemAtPath:cacheDir error:nil];
}
@end


当使用是就调用,传入url 存储,读取时先判断文件存在不存在,不存在,就获取,存在就读取本地数据。

然后在清除缓存时,将此缓存一并清除。

你可能感兴趣的:(ios,NSKeyedArchiver,iOS数据持久化,iOS缓存策略)