NSCoding NSKeyedArchiver NSKeyedUnarchiver

来源:互联网 发布:帝国cms视频教程 编辑:程序博客网 时间:2024/06/03 22:59

概述

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

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 = 0x7f95a1d4efe0age = 5color = 8weight = 58.000000otherAnimal = 0x7f95a1d52700age = 5color = 8weight = 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 = 0mutableData length = 0mutableData length = 396animalNum = 3animal1 = 0x7fc7a0f505c0, animal2 = 0x7fc7a0f4ef30, animal3 = 0x7fc7a0f4fc90age = 15color = 18weight = 158.000000age = 25color = 28weight = 258.000000age = 35color = 38weight = 358.000000otherAnimalNum = 3otherAnimal1 = 0x7fc7a0f544f0, otherAnimal2 = 0x7fc7a0f544d0, otherAnimal3 = 0x7fc7a0f54350age = 15color = 18weight = 158.000000age = 25color = 28weight = 258.000000age = 35color = 38weight = 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 = 0x7fc1e95c24c0age = 15color = 18weight = 158.000000age = 25color = 28weight = 258.000000otherAnimalDict = 0x7fc1e95c62d0, otherAnimal1 = 0x7fc1e95c5b80, otherAnimal2 = 0x7fc1e95c5f60age = 15color = 18weight = 158.000000age = 25color = 28weight = 258.000000
1 0
原创粉丝点击