foundation——NSCoding NSKeyedArchiver NSKeyedUnarchiver

概述

  • 归档与恢复完全类似于其他语言中的序列化和反序列化
  • 归档(序列化)是把对象转换为可保存、可传输的数据流
  • 恢复(反序列化)是从数据流中恢复对象

NSCoding

@protocol NSCoding

- (void)encodeWithCoder:(NSCoder *)aCoder;
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder; // NS_DESIGNATED_INITIALIZER

@end
@interface FBAnimal : NSObject <NSCoding>

- (instancetype)initWithAge:(int)age andColor:(int)color andWeight:(double)weight;

@property (nonatomic) int age;
@property (nonatomic) int color;
@property (nonatomic) double weight;

@end

@implementation FBAnimal

- (instancetype)initWithAge:(int)age andColor:(int)color andWeight:(double)weight
{
    self = [super init];
    if(self)
    {
        self.age = age;
        self.color = color;
        self.weight = weight;
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeInt:self.age forKey:@"age"];
    [aCoder encodeInt:self.color forKey:@"color"];
    [aCoder encodeDouble:self.weight forKey:@"weight"];
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder;
{
    self.age = [aDecoder decodeIntForKey:@"age"];
    self.color = [aDecoder decodeIntForKey:@"color"];
    self.weight = [aDecoder decodeDoubleForKey:@"weight"];
    return self;
}

-(void)info
{
    NSLog(@"age = %d", self.age);
    NSLog(@"color = %d", self.color);
    NSLog(@"weight = %f", self.weight);
}

@end

NSKeyedArchiver

- (void)encodeObject:(nullable id)objv forKey:(NSString *)key;
- (void)encodeConditionalObject:(nullable id)objv forKey:(NSString *)key;
- (void)encodeBool:(BOOL)boolv forKey:(NSString *)key;
- (void)encodeInt:(int)intv forKey:(NSString *)key;	// native int
- (void)encodeInt32:(int32_t)intv forKey:(NSString *)key;
- (void)encodeInt64:(int64_t)intv forKey:(NSString *)key;
- (void)encodeFloat:(float)realv forKey:(NSString *)key;
- (void)encodeDouble:(double)realv forKey:(NSString *)key;
- (void)encodeBytes:(nullable const uint8_t *)bytesp length:(NSUInteger)lenv forKey:(NSString *)key;
encode各种数据类型,encodeObject本质就是调用object的encodeWithCoder:

NSKeyedUnarchiver

- (nullable id)decodeObjectForKey:(NSString *)key;
- (BOOL)decodeBoolForKey:(NSString *)key;
- (int)decodeIntForKey:(NSString *)key;		// may raise a range exception
- (int32_t)decodeInt32ForKey:(NSString *)key;
- (int64_t)decodeInt64ForKey:(NSString *)key;
- (float)decodeFloatForKey:(NSString *)key;
- (double)decodeDoubleForKey:(NSString *)key;
- (nullable const uint8_t *)decodeBytesForKey:(NSString *)key returnedLength:(nullable NSUInteger *)lengthp NS_RETURNS_INNER_POINTER;	// returned bytes immutable, and they go away with the unarchiver, not the containing autorelease pool
decode各种数据类型,decodeObjectForKey的本质就是调用object的initWithCoder:

归档和恢复单一对象

NSKeyedArchiver

+ (NSData *)archivedDataWithRootObject:(id)rootObject;
+ (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path;
分析:
  • 前者归档(序列化)单一对象到NSData
  • 后者归档(序列化)单一对象到文件中
  • 上面方法的本质是生成一个NSKeyedArchiver实例对象,然后调用rootObject的encodeWithCoder:,把生成的NSKeyedArchiver实例对象作为参数传入,在encodeWithCoder:中完成归档(序列化)到NSData中,只不过前者直接返回NSData,后者则多了一个步骤把NSData写入本地文件

NSKeyedUnarchiver

+ (nullable id)unarchiveObjectWithData:(NSData *)data;
+ (nullable id)unarchiveObjectWithFile:(NSString *)path;
分析:
  • 前者恢复(反序列化)NSData到单一对象
  • 后者恢复(反序列化)文件到单一对象
  • 上面方法的本质是生成一个NSKeyedUnarchiver实例对象(data作为数据传入),再生成一个要恢复的目标对象(data中保存了类型相关信息,根据类型相关信息生成目标实例对象),然后调用目标对象的initWithCoder:,把生成的NSKeyedUnarchiver实例对象作为参数传入,在initWithCoder:中完成恢复(反序列化),最后返回恢复(反序列化)完成的目标实例对象,前者直接使用NSData传入序列化数据,后者则多了一个步骤把文件读入到NSData
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
NSString *file = [NSString stringWithFormat:@"%@/%@", docDir, @"animal.archive"];
   
FBAnimal *animal = [[FBAnimal alloc] initWithAge:5 andColor:8 andWeight:58];
[NSKeyedArchiver archiveRootObject:animal toFile:file];
    
FBAnimal *otherAnimal = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
    
NSLog(@"animal = %p", animal);
[animal info];
NSLog(@"otherAnimal = %p", otherAnimal);
[otherAnimal info];
output:
animal = 0x7f95a1d4efe0
age = 5
color = 8
weight = 58.000000
otherAnimal = 0x7f95a1d52700
age = 5
color = 8
weight = 58.000000
注:animal和otherAnimal指向不同的实例对象,但是内容相同
结论:
  • 归档(序列化)对象的本质是调用对象的encodeWithCoder:
  • 恢复(反序列化)对象的本质是调用对象的initWithCoder:
  • 对象要支持归档(序列化)和恢复(反序列化)必须实现NSCoding protocol

归档和恢复任意多个对象

NSKeyedArchiver

- (instancetype)initForWritingWithMutableData:(NSMutableData *)data;
分析:
  • 使用一个NSMutableData类型作为参数传入,然后不断encodeXXX:forKey:要归档(序列化)的数据

NSKeyedUnarchiver

- (instancetype)initForReadingWithData:(NSData *)data;
分析:
  • 使用一个NSData(已经序列化的源数据)类型作为参数传入,然后不断调用decodeXXX:forKey:要恢复(反序列化)的数据
NSMutableData *mutableData = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mutableData];
    
FBAnimal *animal1 = [[FBAnimal alloc] initWithAge:15 andColor:18 andWeight:158];
FBAnimal *animal2 = [[FBAnimal alloc] initWithAge:25 andColor:28 andWeight:258];
FBAnimal *animal3 = [[FBAnimal alloc] initWithAge:35 andColor:38 andWeight:358];
int animalNum = 3;
NSLog(@"mutableData length = %lu", mutableData.length);
[archiver encodeInt:animalNum forKey:@"animalNum"];
[archiver encodeObject:animal1 forKey:@"animal1"];
[archiver encodeObject:animal2 forKey:@"animal2"];
[archiver encodeObject:animal3 forKey:@"animal3"];
NSLog(@"mutableData length = %lu", mutableData.length);
[archiver finishEncoding];
NSLog(@"mutableData length = %lu", mutableData.length);
    
NSLog(@"animalNum = %d", animalNum);
NSLog(@"animal1 = %p, animal2 = %p, animal3 = %p", animal1, animal2, animal3);
[animal1 info];
[animal2 info];
[animal3 info];
    
NSData *data = [mutableData copy];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
data = nil;
int otherAnimalNum = [unarchiver decodeIntForKey:@"animalNum"];
FBAnimal *otherAnimal3 = [unarchiver decodeObjectForKey:@"animal3"];
FBAnimal *otherAnimal2 = [unarchiver decodeObjectForKey:@"animal2"];
FBAnimal *otherAnimal1 = [unarchiver decodeObjectForKey:@"animal1"];
    
NSLog(@"otherAnimalNum = %d", otherAnimalNum);
NSLog(@"otherAnimal1 = %p, otherAnimal2 = %p, otherAnimal3 = %p", otherAnimal1, otherAnimal2, otherAnimal3);
[otherAnimal1 info];
[otherAnimal2 info];
[otherAnimal3 info];
[unarchiver finishDecoding];
output:
mutableData length = 0
mutableData length = 0
mutableData length = 396
animalNum = 3
animal1 = 0x7fc7a0f505c0, animal2 = 0x7fc7a0f4ef30, animal3 = 0x7fc7a0f4fc90
age = 15
color = 18
weight = 158.000000
age = 25
color = 28
weight = 258.000000
age = 35
color = 38
weight = 358.000000
otherAnimalNum = 3
otherAnimal1 = 0x7fc7a0f544f0, otherAnimal2 = 0x7fc7a0f544d0, otherAnimal3 = 0x7fc7a0f54350
age = 15
color = 18
weight = 158.000000
age = 25
color = 28
weight = 258.000000
age = 35
color = 38
weight = 358.000000
分析:
  • 归档(序列化)的时候,先把encode的数据放入NSKeyedArchiver实例对象自身的缓存,只有调用finishEncoding后,才会把NSKeyedArchiver的数据缓存copy到NSMutableData
  • 恢复(反序列化)的时候,先把NSData的数据缓存copy到NSKeyedUnarchiver实例对象自身的缓存,然后对NSKeyedUnarchiver实例对象自身的缓存decode,finishDecode结束decode

深复制应用

FBAnimal *animal1 = [[FBAnimal alloc] initWithAge:15 andColor:18 andWeight:158];
FBAnimal *animal2 = [[FBAnimal alloc] initWithAge:25 andColor:28 andWeight:258];
NSDictionary *animalDict = [NSDictionary dictionaryWithObjectsAndKeys:animal1, @"harry", animal2, @"tom", nil];

NSData *animalData = [NSKeyedArchiver archivedDataWithRootObject:animalDict];
NSDictionary *otherAnimalDict = [NSKeyedUnarchiver unarchiveObjectWithData:animalData];
    
FBAnimal *otherAnimal1 = [otherAnimalDict objectForKey:@"harry"];
FBAnimal *otherAnimal2 = [otherAnimalDict objectForKey:@"tom"];
    
NSLog(@"animalDict = %p, animal1 = %p, animal2 = %p", animalDict, animal1, animal2);
[animal1 info];
[animal2 info];
NSLog(@"otherAnimalDict = %p, otherAnimal1 = %p, otherAnimal2 = %p", otherAnimalDict, otherAnimal1, otherAnimal2);
[otherAnimal1 info];
[otherAnimal2 info];
output:
animalDict = 0x7fc1e95c41d0, animal1 = 0x7fc1e95c0160, animal2 = 0x7fc1e95c24c0
age = 15
color = 18
weight = 158.000000
age = 25
color = 28
weight = 258.000000
otherAnimalDict = 0x7fc1e95c62d0, otherAnimal1 = 0x7fc1e95c5b80, otherAnimal2 = 0x7fc1e95c5f60
age = 15
color = 18
weight = 158.000000
age = 25
color = 28
weight = 258.000000
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值