zoukankan      html  css  js  c++  java
  • OC基础17:归档

      "OC基础"这个分类的文章是我在自学Stephen G.Kochan的《Objective-C程序设计第6版》过程中的笔记。

    1、归档即是用某种格式把一个或多个对象保存起来,以便以后还原回来的一个过程。一般归档数据有两种方法:属性列表归档和带键值的归档。

    2、使用XML属性列表进行归档:

       (1)、Mac OS X上的应用程序使用XML属性列表(或plists)来存储诸如默认参数选择、应用程序设置和配置信息这样的一些数据。然而这些列表的归档用途是有限的,因为当某个数据结构创建属性列表时,没有保存特定的对象类,没有存储对同一对象的多个引用,也没有保持对象的可变性;

       (2)、如果你的对象是NSString、NSDictionary、NSArray、NSData或NSNumber对象,你可以使用在这些类中实现的writeToFile:atomically方法将数据写到文件中。该方法可以使用XML属性列表的格式写出数据。以下代码演示了如何将字典作为属性列表写入文件中,和如何读取出来:

           ...

           NSDictionary *glossary = [NSDictionary dictionaryWithObjectsAndKeys:  

                                      @"A class defined so other class can inherit from it.",@"abstract class",  

                                      @"To implement all the methods defined in a protocol.",@"adopt",  

                                      @"Storing an object for later use.",@"archiving",  

                                      nil  

                                      ];  

               if([glossary writeToFile:@"glossary" atomically:YES] == NO)  

                 NSLog(@"Save to file failed!");  

               ...

               NSDictionary *readgloss;

               readgloss = [NSDictionary dictionaryWithContentsOfFile:@"glossary"];

               for(NSString *key in readgloss)  {

                 NSLog(@"%@: %@",key,[readgloss objectForKey:key]);   

               }

               ...

       (3)、其中writeToFile:atomically:消息被发送给字典对象glossary,使字典以属性列表的形式写入到文件glossary中。atomically参数被设置为YES,表示希望首先将字典写入临时备份文件中,并且一旦成功,再把最终数据转移到名为glossary的制定文件中。这是一种安全措施,它保护文件在一些情况下(如系统在执行操作的过程中崩溃时)免受破坏。在这种情况下原始的glossary文件(如果该文件已经存在)不会受到损害;

       (4)、writeToFile:atomically:所创建的glossary文件,内容一般是这样的:

    <dict>  

        <key>abstract class</key>  

        <string>A class defined so other class can inherit from it.</string>  

        <key>adopt</key>  

        <string>To implement all the methods defined in a protocol.</string>  

        <key>archiving</key>  

        <string>Storing an object for later use.</string>  

    </dict> 

       (5)、根据字典创建属性列表时,字典中的键必须全都是NSString对象。数组的元素或字典中的值可以是NSString、NSArray、NSDictionary、NSData或NSNumber等其他对象;

       (6)、如果要将文件中的XML属性列表读入程序中,要使用dictionaryWithContentsOfFile:方法或arrayWithContentsOfFile:方法。要读取数据则用dataWithContentsOfFile:方法,要读取字符串对象则用stringWithContentsOfFile:方法。

    3、使用NSKeyedArchiver归档:

       (1)、要将各种类型的对象(不仅仅是字符串、数组和字典类型的对象)存储到文件中,有一种更灵活的方法,就是利用NSKeyedArchiver创建带键的档案来完成;

       (2)、在带键的归档中,每个归档字段都有一个名称。归档某个对象时,会为它提供一个名称,即键。从归档中检索该对象时,是根据这个键来检索的。这样可以按照任意的顺序将对象写入归档并进行检索。另外,如果向类添加了新的实例变量或删除了实例变量,程序也可以进行处理;

       (3)、另外,iPhone SDK中没有提供NSArchiver。如果想在iPhone上使用归档功能,则必须使用NSKeyedArchiver;

       (4)、以下代码演示了如何归档和读取:

           ...

           NSDictionary *glossary = [NSDictionary dictionaryWithObjectsAndKeys:  

                                      @"A class defined so other class can inherit from it.",@"abstract class",  

                                      @"To implement all the methods defined in a protocol.",@"adopt",  

                                      @"Storing an object for later use.",@"archiving",  

                                      nil  

                                      ];  

           [NSKeyedArchiver archiveRootObject:glossary toFile:@"glossary.archive"];  

           ...

           NSDictionary *readglossary

           readglossary = [NSKeyedUnarchiver unarchiveObjectWithFile:@"glossary.archive"];  

           for(NSString *key in readglossary)  {

             NSLog(@"%@: %@",key,[readglossary objectForKey:key]);

           }

           ...

    4、归档自定义类:

       (1)、归档自定义类,首先要实现<NSCoding>协议,然后实现encodeWithCoder方法和initWithCoder方法;

       (2)、以AddressCard类为例,首先要实现<NSCoding>协议:

           @interface AddressCard: NSObject <NSCoding>

           然后在@implementation部分添加以下方法:

           -(void) encodeWithCoder: (NSCoder *) encoder {

             [super encodeWithCoder: encoder];

             [encoder encodeObject: name forKey: @ “AddressCardName”];

             [encoder encodeObject: email forKey: @ “AddressCardEmail”];

           }

           -(id) initWithCoder: (NSCoder *) decoder {

             self = [super initWithCoder: decoder];

             name = [decoder decodeObjectForKey: @”AddressCardName”];

             email = [decoder decodeObjectForKey: @”AddressCardEmail”];

             return self;

           }

       (3)、由于name和email两个变量都是NSString类对象,所以可以使用encodeWithObject:方法对它们进行编码;

       (4)、有可能会有子类继承了实例变量并且也进行归档,那么如果某个实例变量归档时的key只使用变量名的,就有可能会出现冲突。所以在指定key的时候,在实例变量名前加上类名;

       (5)、如果父类也有编码和解码方法,才需要使用super语句;

       (6)、bool、int、float和double等基本数据类型有各自对应的编码和解码方法;

       (7)、归档和解码的方法如下:

           ...

           if([NSKeyedArchiver archiveRootObject: ac toFile: @”addresscard.arch”] == NO){

           //ac是一个AddressCard类的对象

             NSLog(@”archiving failed”);

           }

           ...

           ac = [NSKeyedUnarchiver unarchiveObjectWithFile: @”addresscard.arch”];

           ...

       (8)、如果一个类中含有多个类型的实例变量,则在重载encodeWithCoder和initWithCoder两个方法的时候,要对应使用不同的编码方法和解码方法,假如一个类Foo,包含了3个不同类型的实例变量,那么重载方法如下:

           ...

           -(void)encodeWithCoder: (NSCoder *) encoder {

             [encoder encodeObject: strVal forKey: @”FooStrVal”];

             [encoder encodeInt: intVal forKey: @”FooIntVal”];

             [encoder encodeFloat: floatVal forKey: @”FooFloatVal”];

           }

           ...

           -(id) initWithCoder: (NSCoder *) decoder {

             strVal = [decoder decodeObjectForKey: @” FooStrVal”];

             intVal = [decoder decodeIntForKey: @” FooIntVal”];

             floatVal = [decoder decodeFloatForKey: @” FooFloatVal”];

             return self;

           }

           ...

    5、使用NSData创建自定义档案:

       (1)、有时可能想收集多个对象,并且将它们存储到单个档案文件中去,那么就要使用到NSData类;

       (2)、以前面的AddressCard类和Foo类为例,两个类都已实现了encodeWithCoder:方法和initWithCoder:方法,那么可以使用encodeObject: forKey:方法把它们作为对象来归档;

       (3)、归档的实现代码如下:

           ...

           NSMutableData *dataArea;

           NSKeyedArchiver *archiver;

           ...

           dataArea = [NSMutableData data];

           archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData: dataArea];

           [archiver encodeObject: myCard forKey: @”myaddcard”];

           [archiver encodeObject: myFoo forKey: @”myfoo”];

           [archiver finishEncoding];

           if([dataArea writeToFile: @”myArchive” atomically: YES] == NO){

             NSLog(@”Archiver failed”);

           }

           ...

       (4)、其实就是使用定义过的encodeWithCode:r方法把对象归档到一个NSKeyedArchiver类对象archiver里,最后使用XML属性列表归档的方法把archiver的内容归档到文件中(archiver的内容会写在dataArea中),在过程中要注意,要向archiver发送一条finishEncoding的消息来结束编码过程;

       (5)、从档案中恢复数据的方法如下:

           ...

           NSData *dataArea;

           NSKeyedUnarchiver *unarchiver;

           ...

           dataArea = [NSData dataWithContentOfFile: @”myArchive”];

           if(! dataArea) {

             NSLog(@”can’t read back archiver file”);

             return 1;

           }

           unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData: dataArea];

           myCard = [unarchiver decodeObjectForKey: @”myaddcard”];

           myFoo = [unarchiver decodeObjectForKey: @”myfoo”];

           [unarchiver finishDecoding];

           ...

       (6)、同样需要注意,最后要发送一条finishDecoding消息给unarchiver对象结束恢复;

    6、可以使用Foundation的归档功能来创建对象的深复制:

       (1)、假设有数组array1并且数组内有数据,可以使用NSData类对象data将它赋值到另一个空数组array2中去,语句如下:

            ...

            data = [NSKeyedArchiver archivedDataWithRootObject: array1];

            array2 = [NSKeyedUnarchiver unarchiveObjectWithData: data];

            ...

       (2)、其实就是将array1的数据归档到data中,然后再恢复到array2中,执行的效果就是完全的深复制了;

       (3)、甚至可以省略中间的data对象,只用一条语句来执行:

           array2 = [NSKeyedUnarchiver unarchiveObjectWithData:

    [NSKeyedArchiver archivedDataWithRootObject: array1]];

  • 相关阅读:
    关键字,保留字
    20181024
    php连接mysql数据并查询
    java 字符串的json格式数据转换成Map集合
    IntelliJ IDEA的一些快捷键
    Java的反射机制简述
    java主函数知识
    单例设计模式---懒汉式的多线程安全隐患
    java的单例设计模式(对象的延时加载)考试专用
    java的单例设计模式
  • 原文地址:https://www.cnblogs.com/shayneyeorg/p/4863465.html
Copyright © 2011-2022 走看看