NSKeyedAchiver&NSKeyUnarchiver的封装
- 归档和解归档是App数据持久化的方法之一。
- 归档和解归档用在遵循了NSCodying协议的对象,比如说字典、数组、字符串等,但也可以把网络请求的Json看做字典去存储。
- 把归档,解归档和移除数据放在了一个工具类里面,创建的详细过程见代码的源文件
- .h文件中封装的方法:
#import <Foundation/Foundation.h>
/**
* 必须NSCoding协议
*/
// 1.josn数据是字典格式 所以存起来毫无压力啊
@interface LXKArchiverTool : NSObject
/**
* 归档对象
*
* @param object 归档对象
* @param keyString 归档的键
* @param pathString 已经是Document路径,只需加后缀
*/
+ (void)archiverObject:(id)object key:(NSString *)keyString filePath:(NSString *)pathString;
/**
* 解归档的对象
*
* @param pathString 已经是Document路径,只需加后缀
* @param keyStirng 归档的键
*
* @return 返回对象
*/
+ (id )unarchiverPath:(NSString *)pathString key:(NSString *)keyStirng;
/**
删除归档的数据
@param pathString 已经是Document路径,只需加后缀
*/
+ (void)removeArchiverObjectFilePath:(NSString *)pathString;
@end
- .m文件中的实现,里面有详细的注释,所以需要了解归档用解归档可以看一下注释:
#import "LXKArchiverTool.h"
@implementation LXKArchiverTool
/**
* 归档对象
*
* @param object 归档对象
* @param keyString 归档的键
* @param pathString 已经是Document路径,只需加后缀
*/
+ (void)archiverObject:(id)object key:(NSString *)keyString filePath:(NSString *)pathString {
if (!object) {
NSLog(@"归档的对象为空");
return;
}
// NSMutableData对象相当于一个数据中转站 将遵循NSCoding协议的对象转换为data数据
NSMutableData *mData = [NSMutableData data];
// 1.创建归档器
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mData];
// 2.将对象进行归档编码并指定对应的键
[archiver encodeObject:object forKey:keyString];
// 3.结束归档编码
[archiver finishEncoding];
// 4.创建归档路径
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
/**因为文件路径在沙河,而斜杠(/)会被认为是在下一个文件目录下
但是我们并没有建立这样一个文件目录 是所以要去除 避免归档失败
其实吧 是因为有习惯把接口当做路径来存储 有/会失败 所以去出去*/
pathString = [pathString stringByReplacingOccurrencesOfString:@"/" withString:@""];
NSString *filePath = [path stringByAppendingPathComponent:pathString];
// 测试时间的时候请勿开启打印
NSLog(@"归档的对象filePath == %@",filePath );
// 5. 写入文件
[mData writeToFile:filePath atomically:YES];
}
/**
* 解归档的对象
*
* @param pathString 已经是Document路径,只需加后缀
* @param keyStirng 归档的键
*
* @return 返回对象
*/
+ (id )unarchiverPath:(NSString *)pathString key:(NSString *)keyStirng {
// 1. 建立解归档的路径
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
pathString = [pathString stringByReplacingOccurrencesOfString:@"/" withString:@""];
NSString *filePath = [path stringByAppendingPathComponent:pathString];
// 2.根据路径查找data数据
NSData *data = [NSData dataWithContentsOfFile:filePath];
// 3.创建解归档器
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
// 4. 取出解归档的对象
id object = [unarchiver decodeObjectForKey:keyStirng];
NSLog(@"解归档的对象filePath == %@",filePath );
if (!object) {
NSLog(@"解归档的对象为空或者路径不对");
return nil;
}
// 通过指定的键将对象解归档出来
return object;
}
/**
删除归档的数据
@param pathString 已经是Document路径,只需加后缀
*/
+ (void)removeArchiverObjectFilePath:(NSString *)pathString {
// 1.创建文件管理器
NSFileManager *defaultManager = [NSFileManager defaultManager];
// 2.查找删除路径
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
pathString = [pathString stringByReplacingOccurrencesOfString:@"/" withString:@""];
NSString *filePath = [path stringByAppendingPathComponent:pathString];
// 3. 如果此路径下存在文件 删除此路径下的文件
if ([defaultManager isDeletableFileAtPath:filePath]) {
[defaultManager removeItemAtPath:filePath error:nil];
}
}
@end
使用和测试时间
补充小知识点,测试一段代码的时长
NSDate *startDate = [NSDate date];
// your code
double dealTime = [[NSDate date] timeIntervalSinceDate:startDate];
// 使用毫秒测试 1s = 1000ms
NSLog(@"codeTime === %f ms", dealTime * 1000);
测试时间
- 常常听别人说归档与解归档使用与大文件并且不常用的文件使用,那我们来看一看存储、读取、删除都花了多少时间吧,为此使用YYCahe来对比一下:
#import "LXKArchiverTool.h"
#import <YYCache.h>
@interface ViewController ()
@property (nonatomic, strong) NSMutableDictionary *responseObject; //想要存储的数据
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_responseObject = [NSMutableDictionary dictionary];
for (NSInteger i = 0; i < 100; i++) {
[_responseObject setObject:[NSString stringWithFormat:@"test %ld",i] forKey:[NSString stringWithFormat:@"test %ld",i] ];
}
// 是路径也是存储的键
NSString *filePath = @"responseObject";
// 1.存储时间
NSDate *tempStartDate = [NSDate date];
[LXKArchiverTool archiverObject:_responseObject key:filePath filePath:filePath];
[self endTimeLogStarDate:tempStartDate];
NSDate *temp2 = [NSDate date];
YYCache *yyCache = [YYCache cacheWithName:filePath];
[yyCache setObject:_responseObject forKey:filePath];
[self endTimeLogStarDate:temp2];
// 2.读取时间
NSDate *temp3 = [NSDate date];
id object = [LXKArchiverTool unarchiverPath:filePath key:filePath];
[self endTimeLogStarDate:temp3];
NSDate *temp4 = [NSDate date];
YYCache *yyCache1 = [YYCache cacheWithName:filePath];
id value = [yyCache1 objectForKey:filePath];
[self endTimeLogStarDate:temp4];
// 3.删除时间
NSDate *temp5 = [NSDate date];
[LXKArchiverTool removeArchiverObjectFilePath:filePath];
[self endTimeLogStarDate:temp5];
NSDate *temp6 = [NSDate date];
YYCache *yyCache2 = [YYCache cacheWithName:filePath];
[yyCache2 removeObjectForKey:filePath];
[self endTimeLogStarDate:temp6];
// 在此可以断点是否删除失败 不用使用原来的对象去打印
id object1 = [LXKArchiverTool unarchiverPath:@"responseObject" key:@"responseObject"];
id value1 = [yyCache objectForKey:@"responseObject"];
}
- (void)endTimeLogStarDate:(NSDate *)startDete {
double dealTime = [[NSDate date] timeIntervalSinceDate:startDete];
// 使用毫秒测试 1s = 1000ms
NSLog(@"endTime === %f ms", dealTime * 1000);
}
@end
- 100个键值对字典对象测试数据:
- 依次是归档时间,YYCache存储时间
- 解归档时间,YYCache读取时间
- 文件管理删除时间,YYCache删除时间
- 1000个键值对字典对象测试数据:
- 10000个键值对字典对象测试数据:
分析:
很明显YYCache是要优于归档的,阶段差距在毫秒上还是挺大的,但是也没有我想象中那么恐怖,还是可以用。
YYCache每一次都重新创建了对象,是因为归档和解归档也是独立的,如果不每一次都创建对象,其实YYCache的读取和删除都比解归档和文件删除快的。
能想到的比较是这样的,YYCache是用了更对的代码实现来换区时间上的优势,不过人家调用也非常好使,不过得出结论是归档和解归档还是可以用的。