现在的位置: 首页 > 综合 > 正文

IOS数据持久化之NSKeyedArchiver

2017年12月07日 ⁄ 综合 ⁄ 共 7841字 ⁄ 字号 评论关闭

数据持久化一般有四张方式,上面我们说了使用NSUserDefaults进行数据持久化,下面我们总结一下使用归档的方式进行数据持久化

归档是一种很常用的文件储存方法,几乎任何类型的对象都能够被归档储存(实际上是一种文件保存的形式)

使用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


总结:与属性列表相比,归档可以写入复杂对象

代码下载



抱歉!评论已关闭.