NSKeyedArchiver 数据归档

前言

  • NSKeyedArchiver 数据归档

    • Objective-C

      1
      2
      @interface NSKeyedArchiver : NSCoder
      @interface NSKeyedUnarchiver : NSCoder
    • Swift

      1
      2
      public class NSKeyedArchiver : NSCoder
      public class NSKeyedUnarchiver : NSCoder
    • 在 OC 语言中,归档是一个过程,即用某种格式来保存一个或多个对象,以便以后还原这些对象。通常,这个过程包括将(多个)对象写入文件中,以便以后读取该对象。可以使用归档的方法进行对象的深复制。

    • 采用归档的形式来保存数据,该数据对象需要遵守 NSCoding 协议,并且该对象对应的类必须提供 encodeWithCoder: 和 initWithCoder: 方法。前一个方法告诉系统怎么对对象进行编码,而后一个方法则是告诉系统怎么对对象进行解码。

    • 缺点:归档的形式来保存数据,只能一次性归档保存以及一次性解压。所以只能针对小量数据,而且对数据操作比较笨拙,即如果想改动数据的某一小部分,还是需要解压整个数据或者归档整个数据。

    • iOS 实现的序列化方式的两种:NSKeyedArchiver,NSPropertyListSerialization。在这两种序列化方式中,NSData 都是序列化的目标。两种方式的不同点在于 NSPropertyListSerialization 是针对数组和字典类型的,而 NSKeyedArchiver 是针对对象的。

1、系统类的归档/反归档

  • Objective-C

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 文件路径
    NSString *achiverPath = [NSHomeDirectory() stringByAppendingString:@"/Desktop/stringAchiverFile"];

    // 待归档的数据
    NSString *string = @"bei jing huan yin nin";

    // 归档,归档到文件
    bool bl = [NSKeyedArchiver archiveRootObject:string toFile:achiverPath];

    // 反归档,从文件反归档
    NSString *strFromAchiverFile = [NSKeyedUnarchiver unarchiveObjectWithFile:achiverPath];
  • Swift

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 文件路径
    let achiverPath: String = NSHomeDirectory().stringByAppendingString("/Desktop/stringAchiverFile")

    // 待归档的数据
    let string: String = "bei jing huan yin nin"

    // 归档,归档到文件
    let bl: Bool = NSKeyedArchiver.archiveRootObject(string, toFile: achiverPath)

    // 反归档,从文件反归档
    let strFromAchiverFile: AnyObject? = NSKeyedUnarchiver.unarchiveObjectWithFile(achiverPath)!

2、自定义类的归档和反归档

  • Objective-C

    • Dog.h

      1
      2
      3
      4
      5
      6
      7
      8
      9
      // 遵守 NSCoding 协议
      @interface Dog : NSObject <NSCoding>

      @property (nonatomic, assign)int age;
      @property (nonatomic, copy)NSString *name;

      + (Dog *)dogWithName:(NSString *)name andAge:(int)age;

      @end
    • Dog.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      // 实现 NSCoding 协议方法
      @implementation Dog

      // 归档 方法,使用编码器将对象编码成二进制数据流,归档(持久化存储)
      - (void)encodeWithCoder:(NSCoder *)aCoder{

      [aCoder encodeInt:self.age forKey:@"age"];
      [aCoder encodeObject:self.name forKey:@"name"];
      }

      // 反归档 方法,将保存在磁盘上的二进制数据流,解码成 OC 对象
      - (id)initWithCoder:(NSCoder *)aDecoder{

      self.age = [aDecoder decodeIntForKey:@"age"];
      self.name = [aDecoder decodeObjectForKey:@"name"];

      return self;
      }

      @end
    • main.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      #import "Dog.h"

      // 文件路径
      NSString *achiverPath = [NSHomeDirectory() stringByAppendingString:@"/Desktop/dogAchiverFile"];

      Dog *dog = [Dog dogWithName:@"xiao hei" andAge:5];

      // 归档

      // 归档到文件
      BOOL bl = [NSKeyedArchiver archiveRootObject:dog toFile:achiverPath];

      // 反归档

      // 从文件反归档
      Dog *dogFromAchiverFile = [NSKeyedUnarchiver unarchiveObjectWithFile:achiverPath];
  • Swift

    • Dog.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      // 遵守 NSCoding 协议
      class Dog: NSObject, NSCoding {

      var name: String
      var age: Int

      init(name: String, age: Int) {
      self.name = name
      self.age = age
      }

      // 归档 方法
      func encodeWithCoder(aCoder: NSCoder) {

      aCoder.encodeObject(self.name, forKey: "name")
      aCoder.encodeInteger(self.age, forKey: "age")
      }

      // 反归档 方法
      required init(coder aDecoder: NSCoder) {

      self.name = aDecoder.decodeObjectForKey("name") as! String
      self.age = aDecoder.decodeIntegerForKey("age")
      }

      override var description: String{
      return String(format: "%@, %d", self.name , self.age)
      }
      }
    • main.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      // 文件路径
      let achiverPath: String = NSHomeDirectory().stringByAppendingString("/Desktop/dogAchiverFile")

      // Dog 类需要遵守 NSCoding 协议,并实现其协议方法
      let dog: Dog = Dog(name: "xiao hei", age: 2)

      // 归档

      // 归档到文件
      let bl: Bool = NSKeyedArchiver.archiveRootObject(dog, toFile: achiverPath)

      // 反归档

      // 从文件反归档
      let dogFromAchiverFile: AnyObject = NSKeyedUnarchiver.unarchiveObjectWithFile(achiverPath)!

3、NSKeyedArchiver 序列化

  • Objective-C

    • main.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      // Cat 类不需要遵守 NSCoding 协议,也不需要其协议方法
      #import “Cat.h”

      // 文件路径
      NSString *achiverPath = [NSHomeDirectory() stringByAppendingString:@"/Desktop/catAchiverFile"];

      // 归档,编码

      Cat *cat1 = [Cat catWithName:@"xiao bai" andAge:2];

      // 设置数据区域
      NSMutableData *achiverDataArea = [NSMutableData data];

      // 开始存储对象,编码

      // 将数据区域链接到 NSKeyedArchiver 对象
      NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:achiverDataArea];

      // 可以存储类的实例变量
      [archiver encodeObject:cat1.name forKey:@"name"];

      // 编码完成
      [archiver finishEncoding];

      // 将存档的数据写入文件
      BOOL bl = [achiverDataArea writeToFile:achiverPath atomically:YES];

      // 反归档,解码

      Cat *cat2 = [[Cat alloc] init];

      // 设置数据区域
      NSData *unarchiverDataArea = [NSData dataWithContentsOfFile:achiverPath];

      // 解码存储在归档文件中的对象

      // 将数据区域链接到 NSKeyedUnarchiver 对象
      NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:unarchiverDataArea];

      // 解码
      cat2.name = [unarchiver decodeObjectForKey:@"name"];

      // 解码完成
      [unarchiver finishDecoding];
  • Swift

    • main.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      // 文件路径
      let archiverPath: String = NSHomeDirectory().stringByAppendingString("/Desktop/catAchiverFile")

      // Cat 类不需要遵守 NSCoding 协议
      let cat1: Cat = Cat(name: "xiao bai", age: 1)

      var cat2: Cat = Cat(name: "", age: 0)

      // 归档,编码

      // 设置数据区域
      let archiverData: NSMutableData = NSMutableData()

      // 开始存储对象,编码

      // 将数据区域链接到 NSKeyedArchiver 对象
      let archiver: NSKeyedArchiver = NSKeyedArchiver(forWritingWithMutableData: archiverData)

      // 编码
      archiver.encodeInteger(cat1.age, forKey: "age")

      // 编码完成
      archiver.finishEncoding()

      // 将存档的数据写入文件
      let bl: Bool = archiverData.writeToFile(archiverPath, atomically: true)

      // 反归档,解码

      // 设置数据区域
      let unarchiverDataArea: NSData = NSData()

      // 解码存储在归档文件中的对象

      // 将数据区域链接到 NSKeyedUnarchiver 对象
      let unarchiver: NSKeyedUnarchiver = NSKeyedUnarchiver(forReadingWithData: unarchiverDataArea)

      // 解码
      cat2.age = unarchiver.decodeIntegerForKey("age")

      // 解码完成
      unarchiver.finishDecoding()
文章目录
  1. 1. 前言
  2. 2. 1、系统类的归档/反归档
  3. 3. 2、自定义类的归档和反归档
  4. 4. 3、NSKeyedArchiver 序列化
隐藏目录