码迷,mamicode.com
首页 > 其他好文 > 详细

[精通Objective-C]归档和序列化

时间:2016-07-13 16:05:22      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:

[精通Objective-C]归档和序列化

参考书籍:《精通Objective-C》【美】 Keith Lee

使用Foundation框架的归档和序列化类可以将对象(对象图)转换为具有独立结构的字节缓冲区。这样就可以将数据写入文件或者传送给其他进程(通常会通过网络)。之后,这些数据可能会被转换回对象并保留相关的对象图。这些类为数据持久化提供了轻量级技巧。序列化处理类能够保存数据和对象在其层次结构中的位置,而归档处理类具有更广泛的用途,它们可以保存数据、数据类型和对象层次结构中对象之间的关系。

目录

归档

NSCoder是一个抽象类,声明了可用于对对象图进行序列化和反序列化的接口。序列化处理可以将对象的信息转换为字节序列,而反序列化处理可以通过字节序列(通过先前的序列化操作获得的)创建对象。

序列化归档

使用NSArchiver类和NSUnarchiver类可以创建序列化归档,这意味着序列化归档中的对象和值必须使用编码时使用的顺序才能解码。此外,在解码序列化归档时,必须解码整个对象图。使用NSArchiver类可以编码对象,以便将其写入文件或做其他用途,而使用NSUnarchiver类可以通过解码归档文件获得对象。

带键值的归档

NSKeyedArchiver类和NSKeyedUnarchiver类是带键值的归档类,即归档中的每个值都可以具有独有的名称和键值。这些键值必须在被编码和解码的对象内具有唯一性。

下面是带键值归档的使用:

        // 使用NSKeyedArchiver类中的archiveRootObject:方法,将名为greeting的NSString实例归档到当前目录的greeting.archive文件中。
        NSString *greeting = @"Hello,World!";
        NSString *cwd = [[NSFileManager defaultManager] currentDirectoryPath];
        NSString *archivePath = [cwd stringByAppendingString:@"/greeting.archive"];
        BOOL result = [NSKeyedArchiver archiveRootObject:greeting toFile:archivePath];

        if (result) {
            // 使用NSKeyedUnarchiver类中的unarchiveObjectWithFile:方法对greeting.archive文件进行解码
            NSString *greeting2 = [NSKeyedUnarchiver unarchiveObjectWithFile:archivePath];
            NSLog(@"%@",greeting2);
        }

编码和解码对象

当使用NSKeyedArchiver类和NSKeyedUnarchiver类执行归档过程时,必须使用遵守NSCoding协议的类。该协议声明了以下两个方法(具体使用会在后面给出):

-(id)initWithCoder:(NSCoder *)aDecoder;

-(void)encodeWithCoder:(NSCoder *)aCoder;

属性列表序列化

使用NSPropertyListSerialization类可以通过编程方式创建属性列表。该类支持以下数据结构:

NSData
NSDate
NSNumber
NSString
NSArray
NSDictionary

下面是一个属性列表序列化的例子,
其中format参数:

NSPropertyListOpenStepFormat // 传统的ASCII码属性列表格式
NSPropertyListXMLFormat_v1_0 // XML属性列表格式
NSPropertyListBinaryFormat_v1_0 // 二进制属性列表格式

options参数:

NSPropertyListImmutable  // 返回的属性列表中含有不可变对象
NSPropertyListMutableContainers  // 返回的属性列表中含有可变容器,但其中的元素不可变
NSPropertyListMutableContainersAndLeaves  // 返回的属性列表中含有可变的容器和元素
        // 序列化属性列表
        NSError *errorStr;
        NSDictionary *data = @{@"FirstName":@"John",@"LastName":@"Doe"};
        NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:data format:NSPropertyListXMLFormat_v1_0 options:0 error:&errorStr];

        // 对属性列表进行反序列化
        NSError *errorStr2;
        NSDictionary *plist= [NSPropertyListSerialization propertyListWithData:plistData options:NSPropertyListImmutable format:NULL error:&errorStr2];
        NSLog(@"%@",plist);

归档对象图示例

下面使用Foundation框架归档API编写一个程序。该程序会通过类层次结构创建一个对象图,然后通过归档操作编码和解码该对象图。

创建对象图

首先创建一个继承于NSObject,遵循NSCoding协议的类Order:

#import <Foundation/Foundation.h>

@interface Order : NSObject <NSCoding>

@property(readonly) NSString *order;

// 自定义初始化方法
-(id)initWithOrder:(NSString *)order;

@end
#import "Order.h"

@implementation Order

-(id)initWithOrder:(NSString *)order{
    if ((self = [super init])) {
        _order = order;
    }
    return self;
}

// 实现NSCoding协议中的归档初始化方法
-(id)initWithCoder:(NSCoder *)aDecoder{
    if ((self = [super init])) {
        _order = [aDecoder decodeObjectForKey:@"ORDER_KEY"];
    }
    return self;
}

// 实现NSCoding协议中的编码方法
-(void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:self.order forKey:@"ORDER_KEY"];
}

-(NSString *)description{
    return [NSString stringWithFormat:@"Order:%@", self.order];
}

@end

类似地,接下来再创建一个继承于Order类的Family类和继承于Family类的SubFamily类:

Family类:

#import "Order.h"

@interface Family : Order

@property(readonly)NSString *family;

-(id)initWithFamily:(NSString *)family order:(NSString *)order;

@end
#import "Family.h"

@implementation Family

-(id)initWithFamily:(NSString *)family order:(NSString *)order{
    if ((self = [super initWithOrder:order])) {
        _family = family;
    }
    return self;
}

// 注意:这里调用的是父类的initWithCoder:方法,而不是init方法
-(id)initWithCoder:(NSCoder *)aDecoder{
    if ((self = [super initWithCoder:aDecoder])) {
        _family = [aDecoder decodeObjectForKey:@"FAMILY_KEY"];
    }
    return self;
}

// 注意:这里调用了父类的编码方法
-(void)encodeWithCoder:(NSCoder *)aCoder{
    [super encodeWithCoder:aCoder];
    [aCoder encodeObject:self.family forKey:@"FAMILY_KEY"];
}

-(NSString *)description{
    return [NSString stringWithFormat:@"Family:%@,%@",self.family,[super description]];
}

@end

SubFamily类:

#import "Family.h"

@interface SubFamily : Family

@property(readonly) NSString *genus;
@property(readonly) NSString *species;

-(id)initWithSpecies:(NSString *)species genus:(NSString *)genus family:(NSString *)family order:(NSString *)order;

@end
#import "SubFamily.h"

@implementation SubFamily

-(id)initWithSpecies:(NSString *)species genus:(NSString *)genus family:(NSString *)family order:(NSString *)order{
    if ((self = [super initWithFamily:family order:order])) {
        _species = species;
        _genus = genus;
    }
    return self;
}

-(id)initWithCoder:(NSCoder *)aDecoder{
    if ((self = [super initWithCoder:aDecoder])) {
        _species = [aDecoder decodeObjectForKey:@"SPECIES_KEY"];
        _genus = [aDecoder decodeObjectForKey:@"GENUS_KEY"];
    }
    return self;
}

-(void)encodeWithCoder:(NSCoder *)aCoder{
    [super encodeWithCoder:aCoder];
    [aCoder encodeObject:self.species forKey:@"SPECIES_KEY"];
    [aCoder encodeObject:self.genus forKey:@"GENUS_KEY"];
}

-(NSString *)description{
    return [NSString stringWithFormat:@"Animal - Species:%@ Genus:%@,%@",self.species,self.genus,[super description]];
}

@end

创建用于归档对象图的类

接下来创建Archiver类:

#import <Foundation/Foundation.h>

@interface Archiver : NSObject

@property(readwrite) NSString *path;

-(BOOL) encodeArchiver:(id)data toFile:(NSString *)file;
-(id) decodeArchiverFromFile:(NSString *) file;

@end
@implementation Archiver

-(id) init{
    if ((self = [super init])) {
        _path = NSTemporaryDirectory();
    }
    return self;
}

-(BOOL) encodeArchiver:(id)data toFile:(NSString *)file{
    NSString *archivePath = [self.path stringByAppendingPathComponent:file];

    // 为了编码数据,创建一个归档对象
    NSMutableData *mdata = [[NSMutableData alloc] init];
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mdata];

    // 编码将简单字符串作为键的数据
    [archiver encodeObject:data forKey:@"FELINE_KEY"];
    [archiver finishEncoding];

    // 将已编码的数据写入文件,返回写入操作的状态
    BOOL result = [mdata writeToFile:archivePath atomically:YES];
    return result;
}

-(id) decodeArchiverFromFile:(NSString *)file{
    // 获取归档文件的路径
    NSString *archivePath = [self.path stringByAppendingPathComponent:file];

    // 为了解码数据,创建解码对象
    NSData *data = [[NSMutableData alloc] initWithContentsOfFile:archivePath];
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];

    // 解码将简单字符串作为键的数据
    id result = [unarchiver decodeObjectForKey:@"FELINE_KEY"];
    [unarchiver finishDecoding];

    return result;
}

@end

测试结果

最后编写main.m文件:

#import <Foundation/Foundation.h>
#import "Archiver.h"
#import "SubFamily.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 为了编码/解码对象图,创建归档对象
        Archiver *archiver = [[Archiver alloc] init];

        // 创建一个对象图并将之归档到文件中
        id animal = [[SubFamily alloc] initWithSpecies:@"Lion" genus:@"Panther" family:@"Felid" order:@"Carnivore"];
        NSLog(@"\n%@",[animal description]);
        NSString *file = @"data.archive";

        if ([archiver encodeArchiver:animal toFile:file]) {
            NSLog(@"You encoded an archive to file %@",[[archiver path] stringByAppendingString:file]);
        }

        // 通过对象图的归档和描述记录,解码对象图
        id data = [archiver decodeArchiverFromFile:file];
        if ([archiver decodeArchiverFromFile:file]) {
            NSLog(@"You decoded an archive from file %@\n%@",[[archiver path] stringByAppendingString:file],[data description]);
        }
    }
    return 0;
}

运行结果:

2016-07-13 13:51:28.799 Archiver[60039:1335323] 
Animal - Species:Lion Genus:Panther,Family:Felid,Order:Carnivore
2016-07-13 13:51:28.800 Archiver[60039:1335323] You encoded an archive to file /var/folders/jz/y4kx8_2n1wj188xflspjrpb80000gn/T/data.archive
2016-07-13 13:51:28.801 Archiver[60039:1335323] You decoded an archive from file /var/folders/jz/y4kx8_2n1wj188xflspjrpb80000gn/T/data.archive
Animal - Species:Lion Genus:Panther,Family:Felid,Order:Carnivore

[精通Objective-C]归档和序列化

标签:

原文地址:http://blog.csdn.net/sps900608/article/details/51898671

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!