归档是一种很常用的文件储存方法,几乎任何类型的对象都能够被归档储存(实际上是一种文件保存的形式)
使用NSKeyedArchiver进行归档、NSKeyedUnarchiver进行接档,这种方式在写入、读出数据之前对数据进行序列化、反序列化操作
一、对简单对象归档
可以使用archiveRootObject对简单对象进行归档
//归档
NSString *homedirectory = NSHomeDirectory();
self.archivefilepath = [homedirectory stringByAppendingPathComponent:@"object.archiver"];
NSString *homepath =[homedirectory stringByAppendingPathComponent:@"my.archiver"];//扩展名可以是任意的
//归档,可以对字符串、数字进行归档,当然了一可以对NSArray,NSDictionary进行归档,归档成功返回YES,失败返回NO
BOOL flag = [NSKeyedArchiver archiveRootObject:@"zhangsan" toFile:homepath];
if(flag){
NSLog(@"数据归档成功");
}else{
NSLog(@"数据归档失败");
}
//接档
NSString *username = [NSKeyedUnarchiver unarchiveObjectWithFile:homepath];
NSLog(@"反归档数据:%@",username);
二、对多个对象归档
对多个对象归档同样是使用NSKeyedArchiver,但是需要在归档的时候使用encodeXXX方法进行归档,最后通过writeToFile方法写入文件
//归档,写数据
CGPoint point = CGPointMake(10,10);
NSString *desc =@"坐标起始点";
NSInteger val = 10;
NSArray *stuArray =[NSArray arrayWithObjects:@"xiaozhang",@"xiaowang",@"Sandy", nil];
NSDictionary *stuInfoDic =[NSDictionary dictionaryWithObjectsAndKeys:@"22",@"age",@"male",@"sex", nil];
NSString *multipath =[homedirectory stringByAppendingPathComponent:@"multi.archiver"];
NSMutableData *mutabledata =[[NSMutableData alloc] init];
NSKeyedArchiver *archiver =[[NSKeyedArchiver alloc] initForWritingWithMutableData:mutabledata];
//对多个文档对象对象归档
[archiver encodeCGPoint:point forKey:@"kpoint"];
[archiver encodeObject:desc forKey:@"kdesc"];
[archiver encodeInteger:val forKey:@"kval"];
[archiver encodeObject:stuArray forKey:@"kstu"];
[archiver encodeObject:stuInfoDic forKey:@"kstuinfo"];
[archiver finishEncoding];
[mutabledata writeToFile:multipath atomically:YES];
//接档,读数据
NSMutableData *unarchiverData =[[NSMutableData alloc] initWithContentsOfFile:multipath];
NSKeyedUnarchiver *unarchiver =[[NSKeyedUnarchiver alloc] initForReadingWithData:unarchiverData];
CGPoint newpoint =[unarchiver decodeCGPointForKey:@"kpoint"];
NSString *newdesc =[unarchiver decodeObjectForKey:@"kdesc"];
NSInteger newval =[unarchiver decodeIntegerForKey:@"kval"];
NSArray *stuNames =[unarchiver decodeObjectForKey:@"kstu"];
NSDictionary *stuInfo =(NSDictionary *)[unarchiver decodeObjectForKey:@"kstuinfo"];
[unarchiver finishDecoding];
NSLog(@"point:%f,%f",newpoint.x,newpoint.y);
NSLog(@"desc:%@",newdesc);
NSLog(@"val:%d",newval);
NSLog(@"Stu Name:%@",stuNames);
NSLog(@"Stu Info:%@",stuInfo);
三、对自定义对象归档
从上面归档的对象来看都是基本数据类型,那么能不能对自己定义类的实例对象进行归档呢,答案是肯定的,在开发过程中我们经常需要用到自定义对象,如MVC中的model层
下面我们来说说对自定义对象进行归档,要实现对自定义对象的归档与接档,需要实现NSCoding与NSCopying协议(具体协议可以参考apple官方文档)
首先新建一个Person对象,继承自NSObject,实现NSCoding与NSCopying协议,定义一些属性,具体代码如下
Person.h
#define kName @"kname"
#define kAge @"kage"
#define kPhone @"kphone"
#define kphoto @"kphoto"
#import <Foundation/Foundation.h>
@interface Person : NSObject<NSCoding,NSCopying>
@property(nonatomic,copy)NSString *name;
@property NSInteger age;
@property (nonatomic,copy)NSString *phone;
@property(nonatomic,copy)UIImage *photo;
@end
Person.m
#import "Person.h"
@implementation Person
@synthesize name = _name;
@synthesize age = _age;
@synthesize phone = _phone;
@synthesize photo = _photo;
-(id)initWithCoder:(NSCoder *)aDecoder{
if(self =[super init]){
_name =[aDecoder decodeObjectForKey:kName];
_age =[aDecoder decodeIntegerForKey:kAge];
_phone = [aDecoder decodeObjectForKey:kPhone];
_photo =[aDecoder decodeObjectForKey:kphoto];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:_name forKey:kName];
[aCoder encodeInteger:_age forKey:kAge];
[aCoder encodeObject:_phone forKey:kPhone];
[aCoder encodeObject:_photo forKey:kphoto];
}
-(id)copyWithZone:(NSZone *)zone{
Person *copy = [[[self class] allocWithZone:zone] init];
copy.name =[self.name copyWithZone:zone];
copy.age = self.age;
copy.phone = [self.phone copyWithZone:zone];
copy.photo =self.photo;
return copy;
}
@end
Person定义了四个字段(名称,年龄,电话,照片)
Person类实现了三个委托方法
//从coder中读取数据,保存到相应的变量中,即反序列化数据
- (id)initWithCoder:(NSCoder *)decoder
;// 读取实例变量,并把这些数据写到coder中去。序列化数据
- (void)encodeWithCoder:(NSCoder *)encoder
//返回这个对象一个新的实例
- (id)copyWithZone:(NSZone *)zone
备注:要将一个自定义对象进行归档,那么这个自定义对象里面的每个属性都是可以被归档的,如果是不能归档的类型,我们可以把他转化为NSValue进行归档,然后在读出来的时候在转化为相应的类。
我们来对Person对象进行归档与接档,首先我们来新建一个Project,新建一个Person类,在UIViewController上面拖放两个Button,一个UIImageView,在UIViewController的类文件中定义一些属性与方法,代码如下:
#define kPersonData @"kpersondata"//归档键值
#import <UIKit/UIKit.h>
#import "Person.h"
@interface LTViewController : UIViewController
-(IBAction)BtnClickArchiver:(id)sender;//归档事件
-(IBAction)BtnClickUnArchiver:(id)sender;//接档事件
@property(nonatomic,strong)IBOutlet UIImageView *headimageview;//头像显示
@property(nonatomic,strong)NSString *archivefilepath;//归档的路径
@end
//
// LTViewController.m
// DataArchiverDemo
//
// Created by admin on 14-10-14.
// Copyright (c) 2014年 com.doubleicon. All rights reserved.
//
#import "LTViewController.h"
@interface LTViewController ()
@end
@implementation LTViewController
@synthesize archivefilepath;
- (void)viewDidLoad
{
NSString *homedirectory = NSHomeDirectory();
self.archivefilepath = [homedirectory stringByAppendingPathComponent:@"object.archiver"];
NSString *homepath =[homedirectory stringByAppendingPathComponent:@"my.archiver"];//扩展名可以是任意的
//归档,可以对字符串、数字进行归档,当然了一可以对NSArray,NSDictionary进行归档,归档成功返回YES,失败返回NO
BOOL flag = [NSKeyedArchiver archiveRootObject:@"zhangsan" toFile:homepath];
if(flag){
NSLog(@"数据归档成功");
}else{
NSLog(@"数据归档失败");
}
//反归档
NSString *username = [NSKeyedUnarchiver unarchiveObjectWithFile:homepath];
NSLog(@"反归档数据:%@",username);
CGPoint point = CGPointMake(10,10);
NSString *desc =@"坐标起始点";
NSInteger val = 10;
NSArray *stuArray =[NSArray arrayWithObjects:@"xiaozhang",@"xiaowang",@"Sandy", nil];
NSDictionary *stuInfoDic =[NSDictionary dictionaryWithObjectsAndKeys:@"22",@"age",@"male",@"sex", nil];
NSString *multipath =[homedirectory stringByAppendingPathComponent:@"multi.archiver"];
NSMutableData *mutabledata =[[NSMutableData alloc] init];
NSKeyedArchiver *archiver =[[NSKeyedArchiver alloc] initForWritingWithMutableData:mutabledata];
//对多个文档对象对象归档
[archiver encodeCGPoint:point forKey:@"kpoint"];
[archiver encodeObject:desc forKey:@"kdesc"];
[archiver encodeInteger:val forKey:@"kval"];
[archiver encodeObject:stuArray forKey:@"kstu"];
[archiver encodeObject:stuInfoDic forKey:@"kstuinfo"];
[archiver finishEncoding];
[mutabledata writeToFile:multipath atomically:YES];
//反归档
NSMutableData *unarchiverData =[[NSMutableData alloc] initWithContentsOfFile:multipath];
NSKeyedUnarchiver *unarchiver =[[NSKeyedUnarchiver alloc] initForReadingWithData:unarchiverData];
CGPoint newpoint =[unarchiver decodeCGPointForKey:@"kpoint"];
NSString *newdesc =[unarchiver decodeObjectForKey:@"kdesc"];
NSInteger newval =[unarchiver decodeIntegerForKey:@"kval"];
NSArray *stuNames =[unarchiver decodeObjectForKey:@"kstu"];
NSDictionary *stuInfo =(NSDictionary *)[unarchiver decodeObjectForKey:@"kstuinfo"];
[unarchiver finishDecoding];
NSLog(@"point:%f,%f",newpoint.x,newpoint.y);
NSLog(@"desc:%@",newdesc);
NSLog(@"val:%d",newval);
NSLog(@"Stu Name:%@",stuNames);
NSLog(@"Stu Info:%@",stuInfo);
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
//自定义对象的归档
-(void)BtnClickArchiver:(id)sender{
Person *person =[[Person alloc] init];
person.name = @"doubleicon";
person.age = 23;
person.photo = [UIImage imageNamed:@"boy"];
person.phone = @"13896459863";
NSMutableData *persondata =[[NSMutableData alloc] init];
NSKeyedArchiver *archiver =[[NSKeyedArchiver alloc] initForWritingWithMutableData:persondata];
[archiver encodeObject:person forKey:kPersonData];
[archiver finishEncoding];
[persondata writeToFile:self.archivefilepath atomically:YES];
NSLog(@"归档对象成功");
}
//自定义对象的接档
-(void)BtnClickUnArchiver:(id)sender{
NSData *persondata =[[NSData alloc] initWithContentsOfFile:self.archivefilepath];
NSKeyedUnarchiver *unarchiver =[[NSKeyedUnarchiver alloc] initForReadingWithData:persondata];
Person *person =[unarchiver decodeObjectForKey:kPersonData];
[unarchiver finishDecoding];
NSString *name =person.name;
NSInteger age =person.age;
NSString *phone = person.phone;
UIImage *image = person.photo;
self.headimageview.image = image;
NSLog(@"Name:%@,Age:%d,Phone:%@",name,age,phone);
NSLog(@"反归档对象成功");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
总结:与属性列表相比,归档可以写入复杂对象