• iOS数据存储之对象归档


    iOS数据存储之对象归档

    对象归档

    对象归档是iOS中数据持久化的一种方式。
    归档是指另一种形式的序列化,但它是任何对象都可以实现的更常规的类型。使用对模型对象进行归档的技术可以轻松将复杂的对象写入文件,然后再从中读取它们。对象归档后将得到一个后缀为.archive的文件

    要使用对象归档,则归档的对象所属类中实现的每个属性都是标量,或者都是遵循NSCoding协议和NSCopying协议的某个类的实例,也就是说,在类的头文件中需要添加如下语句
    可以编解码的条件是:对象要实现<>中的两个协议,也就是说 要定义自己的编解码规则,在头文件中声明遵循下列两个协议

    @interface BIDFourLines : NSObject <NSCoding, NSCopying>
    

    遵循NSCoding协议

    NSCoding中声明了两个方法,其中一个用于将对象编码到归档中,另一个方法对归档解码来创建一个新对象。
    归档时要实现的方法为:

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

    可以使用KVC(Key-Value Coding,键值编码)对对象和原生数据类型进行编码和解码。
    若要对对象进行归档,必须使用正确的编码方法将所有实例变量编码成encoder。
    在解码时,实现一个通过NSCoder解码的对象初始化方法,就可以恢复之前归档的对象。解码时要实现的方法为:

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

    总的来说,只要对象实现了上面提到的两个方法,就可以对所有对象的属性进行编码和解码,然后就可以对对象进行归档,并且可以将其写入归档或者从归档中读取它们。

    实现NSCopying协议

    除了要遵循NSCoding协议外,还要求要使用归档的类实现NSCoping协议。这个协议中有一个copywithZone方法,

    - (id)copyWithZone:(NSZone *)zone;
    

    用来复制对象。其实现与inetWitheCoder非常相似,只需创建一个同一类的新实例,然后将新实例的所有属性都设置为与该对象属性相同的值。

    案例

    还是用之前那个案例来熟悉整个对象归档机制
    首先仍然是获取应用的Documents文件夹,然后在该文件夹下创建一个归档文件,代码如下:

    - (NSString *)dataFilePath
    {
        NSArray *paths = NSSearchPathForDirectoriesInDomain
        ( NSDocumentDirectory, NSUserDomainMask, YES);
        
        NSString *documentsDirectory = [paths objectAtIndex:0];
        return [documentsDirectory stringByAppendingPathComponent:@"data.archive"];
    }
    

    实现编码:
    定义了一个用于编码的键,并且是常量

    static NSString * const kRootKey = @"kRootKey";
    
    //实现编码,定义自己的翻译规则,用kLinesKey来对lines进行编码
    - (void)encodeWithCoder:(NSCoder *)aCoder;
    {   
        [aCoder encodeObject:self.lines forKey:kLinesKey];
    }
    

    实现了编码后,就可以对对象进行归档了,对象归档发生在程序从前台退出之后。
    具体的归档代码如下:

    - (void)applicationWillResignActive:(NSNotification *)notification
    {
        //获取归档文件路径
        NSString *filePath = [self dataFilePath];
        
        //把文本框组中的数据读取出来,放进lines中
        BIDFourLines *fourLines = [[BIDFourLines alloc] init];
        fourLines.lines = [self.lineFields valueForKey:@"text"];
        
        //声明一个二进制流 data,开辟了一个空间
        NSMutableData *data = [[NSMutableData alloc] init];
        //声明一个归档类,把归档类的内容放入data中
        NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]
                                     initForWritingWithMutableData:data];
                                     
        //用kRootKey进行编码
        [archiver encodeObject:fourLines forKey:kRootKey];
        
        //结束编码
        [archiver finishEncoding];
        
        //编码结束后,归档类的内容已经放入data中了,此时data仍然驻留在内存中,需要写入文件中
        [data writeToFile:filePath atomically:YES];
    }
    

    实现解码:

    //实现解码
    - (id)initWithCoder:(NSCoder *)aDecoder
    {   
        self = [super init];
    
    
        if (self) {
            self.lines = [aDecoder decodeObjectForKey:kLinesKey];
        }   
        return self;
    }
    

    实现解码后,就能够对对象取消归档,这个过程发生在程序重新加载的时候,具体代码如下:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        //查找归档文件路径
        NSString *filePath = [self dataFilePath];
        if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        
            //用归档文件中的数据初始化data
            NSData *data = [[NSMutableData alloc]
                            initWithContentsOfFile:filePath];
                            
        //声明一个解归档对象
        NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]
        
        //把data中的数据复制给解归档对象                                     initForReadingWithData:data];
    
        //用kRootKey进行解码
        BIDFourLines *fourLines = [unarchiver decodeObjectForKey:kRootKey];
      
        //结束解码
        [unarchiver finishDecoding];
    
            //把lines中的数据填入到显示的文本框中
            for (int i = 0; i < 4; i++) {
                UITextField *theField = self.lineFields[i];
                theField.text = fourLines.lines[i];
            }
        }
        
        //订阅消息,观察自身是否退到后台,若从前台退出,则运行applicationWillResigneActive方法,进行归档
        UIApplication *app = [UIApplication sharedApplication];
        [[NSNotificationCenter defaultCenter]
         addObserver:self
         selector:@selector(applicationWillResignActive:)
         name:UIApplicationWillResignActiveNotification
         object:app];
    }
    

    结果

    归档后,将在应用的Documents文件夹下生成data.archive文件,如下图
    enter description here

    用Notepad++打开该文件会看到一堆乱码,如下图:

    enter description here

    总结

    我感觉对象归档方法有点类似于加密,要对某个对象归档,首先要定义一套对象的编码机制,而这个编码机制就可理解为“加密”,而对对象取消归档的时候,我们用对应的解码机制来操作,也就是说,解码机制就是与“加密”对应的“解密”。也可以把编码和解码理解为一套“翻译规则”,在对象归档阶段,编译器按照用户定义的“翻译规则”将对象的各种属性翻译成底层的数据形式,在对象取消归档阶段,编译器又按照用户定义的“翻译规则”将之前保存的数据“翻译”回有意义的数据。对象归档可以层层嵌套,也就是说,对象可以包含一个自定义的对象,只要被包含的这个对象也遵循NSCoding和NSCopying协议,有了这个嵌套,我们就可以把相对复杂的对象保存起来。
    从本质上看,对象归档是以文件的形式保存数据的,使用的时候到相应路径下去读取文件内容就可以了。归档后的数据文件是保密的,无法直接查看,而属性列表是明文,是可以直接查看的。

  • 相关阅读:
    Jenkins 的安装部署
    Python /usr/bin/python
    java学习基础 项目
    Java 并行与并发
    c# 将一个窗体显示在主窗体中
    java.io.IOException: open failed: EACCES (Permission denied) 问题解决
    android中创建模拟器的 SDCard
    Android学习笔记__2__Android工程目录结构
    Android学习笔记__3__Android应用程序组成
    Android学习笔记__1__Android体系架构
  • 原文地址:https://www.cnblogs.com/scut-linmaojiang/p/5287824.html
Copyright © 2020-2023  润新知