在学习IPhone开发中,有时我们不可避免的需要永久化存储一些数据,以供应用下次打开该应用时,方便我们操作,这就有点像单机游戏中得存档一样,我们读取存档,就可以在存档的位置继续游戏.

    概念:归档是把对象写入文件保存在硬盘中,当再次重新打开程序时,可以还原这些对象.

    那么在OC中应该怎样实现这种存档的机制?

在OC中有四中类型是可以直接使用WriteFile进行归档的,分别是NSString,NSArray,NSDictionary,NSData.(当然它们的子类肯定也是可以的)

下面是一个示例:

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
    @autoreleasepool {
        NSString * str = @"你好";
        NSDictionary * dic = [NSDictionary dictionaryWithObjectsAndKeys:@"One",@"1",@"Two",@"2",@"Three",@"3",nil] ;
        NSData * data = [str dataUsingEncoding:NSUTF8StringEncoding];
        NSArray * array = [NSArray arrayWithObjects:str,dic,data,nil];
        [str writeToFile:@"/Users/qzy/Desktop/my1.data" atomically:YES encoding:NSUTF8StringEncoding error:nil];
        [dic writeToFile:@"/Users/qzy/Desktop/my2.data" atomically:YES];
        [data writeToFile:@"/Users/qzy/Desktop/my3.data" atomically:YES];
        [array writeToFile:@"/Users/qzy/Desktop/my4.data" atomically:YES];
    }
    return 0;
}

    这里有需要注意的是,一个文件中只能写入一种对象,否则将会出错,另外atomically属性用来保护文件安全,在我们写入的时候会创建一个新文件,将内容写入后,会替换掉原来的文件,这样避免文件被破坏,可也造成了内存的浪费.

    但是在实现工程中我们写入文件的数据往往是自定义的数据结构,这个时候想要将数据写入文件并在下次启动程序时能够顺利读取存档,就又要借助NSData这个数据类型以及<NSCoding>协议,要使用这个协议需要实现它的两个方法

- (void)encodeWithCoder:(NSCoder *)aCoder;
- (id)initWithCoder:(NSCoder *)aDecoder;

示例:

//定义Person头文件
#import <Foundation/Foundation.h>
//如果我们想把自定义类的对象进行永久保存,那么就必须要归档
//但是归档类制定了一个NSCoding 协议
//所有要归档的类必须要遵守协议实现规范的方法

@interface Person : NSObject <NSCoding>//在此处增加协议
{
    int _age;
    NSString *_name;
}
@property (nonatomic) int age;
@property (nonatomic,copy) NSString *name;
@end



//Person方法体实现
#import "Person.h"
#define AGE @"age"
#define NAME @"name"

@implementation Person
//归档的时候调用的方法

- (void)encodeWithCoder:(NSCoder *)aCoder{
    //[super encodeWithCoder:aCoder];如果父类也遵循归档协议这里需要调用该语句
    [aCoder encodeInt:self.age forKey:AGE];
    [aCoder encodeObject:self.name forKey:NAME];
}
//解归档的时候要调用的函数
- (id)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super init]) {//如果父类也遵守归档协议那么这里要调用 [super initWithCoder:];
        self.age = [aDecoder decodeIntForKey:AGE];
        self.name = [aDecoder decodeObjectForKey:NAME];
    }
    return self;
}
@end

//main.c
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
#if 0
       //系统自带类的对象进行归档
        NSArray *array = @[@"ios",@"oc"];
        //对数组归档
        //归档的类 包括这个类中的元素 所属类的都必须要遵守NSCoding 协议才能归档和解归档

        BOOL ret = [NSKeyedArchiver archiveRootObject:array toFile:@"/Users/apple/Desktop/arr.data"];
        if (ret) {
            NSLog(@"归档成功");
        }else{
            NSLog(@"归档失败");
        }
#else
        //解档之后要注意强引用 防止释放
        //解归档、读档
        NSArray *array = [[NSKeyedUnarchiver unarchiveObjectWithFile:@"/Users/apple/Desktop/arr.data"] retain];
        NSLog(@"array = %@",array);
        
#endif
        
        //自定义类的对象进行归档
        //如果自定义的类对象要进行归档那么这个对象的属性所属的类也必须要遵守归档协议
        
        Person *xiaohong = [[Person alloc] init];
        
        xiaohong.age = 2;
        xiaohong.name = @"xiaohong";
        //对xiaohong指向的对象进行归档(永久保存)
        BOOL ret2 = [NSKeyedArchiver archiveRootObject:xiaohong toFile:@"/Users/apple/Desktop/Person.data"];
        if (ret2) {
            NSLog(@"人物归档成功");
        }else {
            NSLog(@"人物归档失败");
        }
        
        //解归档
        
        Person *person = [(Person *)[NSKeyedUnarchiver unarchiveObjectWithFile:@"/Users/apple/Desktop/Person.data"] retain];
        NSLog(@"age = %d name = %@",person.age,person.name);
        
//#endif
        
        
    }
    return 0;
}

    在上述代码中,发现在解归档的时候,如果不添加retain关键字,该对象在关闭ARC的情况下会自动释放(有点像我们创建对象时后面添加了autorelease),因此需要retain一次,避免出现错误!