您的位置:首页 > 其它

数据缓存——NSKeyedArchiver归档(NSCoding)

2016-04-15 23:06 253 查看
NSKeyedArchiver归档(NSCoding)

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保存,则文件保存内容是可见的,且无须自定义文件;否则需要自定义文件及其存储路径,当然保存的文件即使打开也是无法识别的乱码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: