面试题答案
一键面试可能遇到的数据一致性问题
- 对象引用循环:如果对象图中存在循环引用,归档和解档过程可能导致无限递归,从而引发崩溃或数据损坏。例如,对象A引用对象B,而对象B又引用对象A。
- 版本兼容性:如果归档后的对象模型发生变化(如添加、删除属性或修改属性类型),解档时可能无法正确恢复对象状态,导致数据不一致。
- 数据丢失:在归档和解档过程中,如果某些属性没有正确处理(如未实现
NSCoding
协议的相关方法),可能会导致这些属性的数据丢失。
确保解档后对象关系与归档前一致的方法
- 实现
NSCoding
协议:自定义对象需要实现NSCoding
协议,确保正确归档和解档对象的属性。 - 处理对象引用:对于对象之间的引用,在归档和解档时要确保引用的正确性。可以通过存储对象的唯一标识符(如对象的内存地址或自定义的ID),在解档时重新建立引用关系。
- 版本控制:在归档数据中添加版本信息,解档时根据版本信息进行相应的处理,以保证兼容性。
Objective - C代码示例
// 自定义对象类
@interface Person : NSObject <NSCoding>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSDate *birthDate;
@property (nonatomic, strong) Person *spouse; // 假设存在对象引用
- (instancetype)initWithName:(NSString *)name birthDate:(NSDate *)birthDate spouse:(Person *)spouse;
@end
@implementation Person
- (instancetype)initWithName:(NSString *)name birthDate:(NSDate *)birthDate spouse:(Person *)spouse {
self = [super init];
if (self) {
_name = name;
_birthDate = birthDate;
_spouse = spouse;
}
return self;
}
// 归档方法
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeObject:self.birthDate forKey:@"birthDate"];
// 处理对象引用,这里存储spouse的内存地址作为唯一标识符
if (self.spouse) {
[aCoder encodeObject:[NSValue valueWithPointer:self.spouse] forKey:@"spouse"];
}
}
// 解档方法
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
NSString *name = [aDecoder decodeObjectForKey:@"name"];
NSDate *birthDate = [aDecoder decodeObjectForKey:@"birthDate"];
NSValue *spouseValue = [aDecoder decodeObjectForKey:@"spouse"];
Person *spouse = nil;
if (spouseValue) {
// 在解档时,通过存储的内存地址重新建立引用
spouse = (__bridge Person *)[spouseValue pointerValue];
}
return [[self class] initWithName:name birthDate:birthDate spouse:spouse];
}
@end
// 归档和解档操作示例
NSData *archiveData;
{
Person *spouse = [[Person alloc] initWithName:@"Spouse Name" birthDate:[NSDate date] spouse:nil];
Person *person = [[Person alloc] initWithName:@"John Doe" birthDate:[NSDate date] spouse:spouse];
archiveData = [NSKeyedArchiver archivedDataWithRootObject:person];
}
Person *unarchivedPerson;
{
unarchivedPerson = [NSKeyedUnarchiver unarchiveObjectWithData:archiveData];
}
在上述代码中,通过实现NSCoding
协议来处理对象的归档和解档。对于对象之间的引用(spouse
属性),通过存储对象的内存地址作为唯一标识符,并在解档时重新建立引用关系,以确保解档后对象之间的关系与归档前一致。同时,可以通过在归档数据中添加版本信息来处理版本兼容性问题,不过上述示例中未包含这部分内容。