数据缓存——NSKeyedArchiver归档(NSCoding)
2016-04-15 23:06
253 查看
NSKeyedArchiver归档(NSCoding)
Demo下载地址
归档是一种很常用的文件储存方法,几乎任何类型的对象都能够被归档储存(实际上是一种文件保存的形式),特别是能够支持自定义类型对象。
一、实现
1、要使的需要存储的对象实现NSCoding协议,从而使他自己满足写二进制数据的能力。即是自己具有序列化的能力。
2、使用NSCoder的子类方法,实现二进制数据的动作,如读或者写。即触发存档过程。
二、使用
1、对单个对象
(1)使用NSUserDefault进行存储等操作
MAC查看路径:
在Xcode5及之前,存放路径:/Users/username/Library/Application Support/iPhoneSimulator/模拟器版本/Applications/UDID/Library 的Preferences文件夹下,自己程序命名.plist。
在Xcode6及之后,路径为:/Users/username/Library/Developer/CoreSimulator/Devices/模拟器UDID/data/Library,Preferences文件夹下。
(2)使用自定义文件进行存储操作
2、对多个对象的归档
三、特别推荐
因为归档必须实现NSCoding协议,且重写方法时,每个属性都应该设置编解码,这样操作起来是比较烦琐的。所以我们可以创建一个基类,在基类里实现NSCoding协议,同时使用runtime进行时设置属性的编解码,而后其他自定义数据类型对象均继承这个基类,则不必再重写烦琐的协议方法了。
注意:
1、通过plist保存的数据是直接显示的,不安全。通过归档方法保存的数据在文件中打开是乱码的,更安全。
2、存储时,如果是通过NSUserDefault保存,则文件保存内容是可见的,且无须自定义文件;否则需要自定义文件及其存储路径,当然保存的文件即使打开也是无法识别的乱码。
Demo下载地址
归档是一种很常用的文件储存方法,几乎任何类型的对象都能够被归档储存(实际上是一种文件保存的形式),特别是能够支持自定义类型对象。
一、实现
1、要使的需要存储的对象实现NSCoding协议,从而使他自己满足写二进制数据的能力。即是自己具有序列化的能力。
2、使用NSCoder的子类方法,实现二进制数据的动作,如读或者写。即触发存档过程。
// 属性编码 向coder中写入数据 -(void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:self.nameforKey:@"name"]; [aCoder encodeInteger:self.ageforKey:@"age"]; }
// 属性解码 读取coder中的数据 -(id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; if (self) { self.name = [aDecoder decodeObjectForKey:@"name"]; self.age = [aDecoderdecodeIntegerForKey:@"age"]; } return self; }
二、使用
1、对单个对象
(1)使用NSUserDefault进行存储等操作
/************************************************************************/ /// 保存归档对象(NSUserDefaults plist文件存储) + (BOOL)saveItem:(id)model key:(NSString *)key { if (model && (key &&0 < key.length)) { NSData *object = [NSKeyedArchiverarchivedDataWithRootObject:model]; [[NSUserDefaultsstandardUserDefaults]setObject:objectforKey:key]; [[NSUserDefaultsstandardUserDefaults]synchronize]; NSLog(@"%@",NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)[0]); returnYES; } returnNO; } + (void)saveItem:(id)model key:(NSString *)key complete:(void (^)(BOOL isSuccess))complete { BOOL isResult = [selfsaveItem:modelkey:key]; if (complete) { complete(isResult); } } /// 读取归档对象(NSUserDefaults plist文件存储) + (id)getItemWithKey:(NSString *)key { if (key &&0 < key.length) { NSData *data = [[NSUserDefaultsstandardUserDefaults]objectForKey:key]; // 解码 id model = [NSKeyedUnarchiverunarchiveObjectWithData:data]; return model; } returnnil; } /// 删除归档对象(NSUserDefaults plist文件存储) + (BOOL)removeItemWithKey:(NSString *)key { if (key &&0 < key.length) { [[NSUserDefaultsstandardUserDefaults]removeObjectForKey:key]; [[NSUserDefaultsstandardUserDefaults]synchronize]; returnYES; } returnNO; } + (void)removeItemWithKey:(NSString *)key complete:(void (^)(BOOL isSuccess))complete { BOOL isResult = [selfremoveItemWithKey:key]; if (complete) { complete(isResult); } } /************************************************************************/
MAC查看路径:
打印路径: NSLog(@"%@",NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]);
在Xcode5及之前,存放路径:/Users/username/Library/Application Support/iPhoneSimulator/模拟器版本/Applications/UDID/Library 的Preferences文件夹下,自己程序命名.plist。
在Xcode6及之后,路径为:/Users/username/Library/Developer/CoreSimulator/Devices/模拟器UDID/data/Library,Preferences文件夹下。
(2)使用自定义文件进行存储操作
/************************************************************************/ ///删除归档对象(自定义文档文件存储) + (BOOL)removeArchivedItemWithPath:(NSString *)fileName { if (fileName &&0 < fileName.length) { NSString *filePath = [selfarchiveFilePath:fileName]; if ([[NSFileManagerdefaultManager]fileExistsAtPath:filePath]) { BOOL isResult = [[NSFileManagerdefaultManager]removeItemAtPath:filePatherror:nil]; return isResult; } } returnNO; } + (void)removeArchivedItemWithPath:(NSString *)fileName complete:(void (^)(BOOL isSuccess))complete { BOOL isResult = [selfremoveArchivedItemWithPath:fileName]; if (complete) { complete(isResult); } } ///保存归档对象(自定义文档文件存储) + (BOOL)saveArchivedItem:(id)model path:(NSString *)fileName { if (model && (fileName &&0 < fileName.length)) { NSString *filePath = [selfarchiveFilePath:fileName]; BOOL isResult = [NSKeyedArchiverarchiveRootObject:modeltoFile:filePath]; return isResult; } returnNO; } + (void)saveArchivedItem:(id)model path:(NSString *)fileName complete:(void (^)(BOOL isSuccess))complete { BOOL isResult = [selfsaveArchivedItem:modelpath:fileName]; if (complete) { complete(isResult); } } ///读取归档对象(自定义文档文件存储) + (id)getArchivedItemWithPath:(NSString *)fileName { if (fileName &&0 < fileName.length) { NSString *filePath = [selfarchiveFilePath:fileName]; // 解码 id model = [NSKeyedUnarchiverunarchiveObjectWithFile:filePath]; return model; } returnnil; } // 路径 + (NSString *)archiveFilePath:(NSString *)fileName { if (!fileName ||0 == fileName.length) { returnnil; } // // 获取根目录(即与document/library/tmp同级) // NSString *homeDictionary = NSHomeDirectory(); // // 添加储存的文件名 // NSString *archivedPath = [homeDictionary stringByAppendingPathComponent:fileName]; // document目录下 NSArray *documentArray =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES); NSString *document = [documentArrayobjectAtIndex:0]; NSString *archivedPath = [documentstringByAppendingPathComponent:fileName]; NSLog(@"filePath %@", archivedPath); return archivedPath; } /************************************************************************/
2、对多个对象的归档
/************************************************************************/ ///多个对象归档 + (BOOL)saveArchivedItems:(NSDictionary *)dict path:(NSString *)fileName { if ((dict &&0 != dict.count) && (fileName &&0 != fileName.length)) { NSString *filePath = [selfarchiveFilePath:fileName]; NSMutableData *data = [[NSMutableDataalloc]init]; NSKeyedArchiver *archvier = [[NSKeyedArchiveralloc]initForWritingWithMutableData:data]; for (NSString *keyin dict.allKeys) { id value = dict[key]; [archvier encodeObject:valueforKey:key]; } [archvier finishEncoding]; BOOL result = [datawriteToFile:filePathatomically:YES]; return result; } returnNO; } + (void)saveArchivedItems:(NSDictionary *)dict path:(NSString *)fileName complete:(void (^)(BOOL isSuccess))complete { BOOL result = [selfsaveArchivedItems:dictpath:fileName]; if (complete) { complete(result); } } ///获取某个归档对象 + (id)getArchivedItemWithKey:(NSString *)key path:(NSString *)fileName { if ((key &&0 != key.length) && (fileName &&0 != fileName.length)) { NSString *filePath = [selfarchiveFilePath:fileName]; NSMutableData *data = [[NSMutableDataalloc]initWithContentsOfFile:filePath]; NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiveralloc]initForReadingWithData:data]; id value = [unarchiverdecodeObjectForKey:key]; [unarchiver finishDecoding]; return value; } returnnil; } /************************************************************************/
三、特别推荐
因为归档必须实现NSCoding协议,且重写方法时,每个属性都应该设置编解码,这样操作起来是比较烦琐的。所以我们可以创建一个基类,在基类里实现NSCoding协议,同时使用runtime进行时设置属性的编解码,而后其他自定义数据类型对象均继承这个基类,则不必再重写烦琐的协议方法了。
.h文件 #import <Foundation/Foundation.h> @interface BaseArchivedObject :NSObject @end
.m文件 #import "BaseArchivedObject.h" #import <objc/runtime.h> @implementation BaseArchivedObject // 解档 - (id)initWithCoder:(NSCoder *)decoder { self = [superinit]; if (self) { unsignedint count =0; // 获取类中所有成员变量名 Ivar *ivar =class_copyIvarList([selfclass], &count); for (int i =0; i < count; i++) { Ivar iva = ivar[i]; constchar *name =ivar_getName(iva); NSString *strName = [NSStringstringWithUTF8String:name]; // 进行解档取值 id value = [decoderdecodeObjectForKey:strName]; // 利用KVC对属性赋值 [selfsetValue:valueforKey:strName]; } free(ivar); } returnself; } // 归档 - (void)encodeWithCoder:(NSCoder *)encoder { unsignedint count; Ivar *ivar =class_copyIvarList([selfclass], &count); for (int i =0; i < count; i++) { Ivar iv = ivar[i]; constchar *name =ivar_getName(iv); NSString *strName = [NSStringstringWithUTF8String:name]; // 利用KVC取值 id value = [selfvalueForKey:strName]; [encoder encodeObject:valueforKey:strName]; } free(ivar); } @end
注意:
1、通过plist保存的数据是直接显示的,不安全。通过归档方法保存的数据在文件中打开是乱码的,更安全。
2、存储时,如果是通过NSUserDefault保存,则文件保存内容是可见的,且无须自定义文件;否则需要自定义文件及其存储路径,当然保存的文件即使打开也是无法识别的乱码。
相关文章推荐
- udisk2阻止自动Mount某些设备
- 什么是闭包,闭包的作用
- Ubuntu登录公司邮箱(Exchange)
- 使用cmake的时候,出现 CMake Error CMAKE_CXX_COMPILER not set错误
- 销售排行榜
- 海空一体战——军种协同应对反介入和区域拒止挑战
- Android 静态广播和动态广播接收顺序
- Matlab学习笔记 figure函数
- Java使用JDBC连接MySQL数据库
- JAVA8 十大新特性详解
- 程序员第45天
- Matlab学习笔记 figure函数
- 老码农的技术理想
- Android中关联源码遇到的问题
- 爆打团队 2016.04.15 站立会议
- 各语言生成随机数
- MZSelectableLabel使用
- 使用word2vec对新浪微博进行情感分析和分类
- 单点接地和多点接地
- 如何将js获取的变量付给jsp中表单的action