您的位置:首页 > 移动开发 > IOS开发

iOS数据持久化

2015-10-12 20:20 375 查看
今天想来聊聊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 存储,读取时先判断文件存在不存在,不存在,就获取,存在就读取本地数据。

然后在清除缓存时,将此缓存一并清除。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: