如何迁移已使用 NSKeyedArchiver 持久化的对象?
How to migrate an object which has been persisted with NSKeyedArchiver?
我正在使用 Archiver 的一个版本,运行 遇到了问题。
在我项目的先前版本中,class、Challenge 被序列化到磁盘
//v1.0
@interface Challenge : NSObject<NSCoding>
{
...
@property (nonatomic,strong) NSString *challengeId;
@property (nonatomic,strong) NSString *title;
@property (nonatomic) BOOL isCompleted;
...
}
现在,在应用程序的 1.1 版中,希望通过添加两个新的@properties 来更改 Challenge 对象。
//v1.1
@interface Challenge : NSObject<NSCoding>
{
...
@property (nonatomic,strong) NSString *challengeId;
@property (nonatomic,strong) NSString *title;
@property (nonatomic) BOOL isCompleted;
...
@property (nonatomic) BOOL isActive;
@property (nonatomic) NSInteger completeCount;
}
我的问题是,当 Archiver 尝试解码 Challenge 对象时,因为存在两个新属性(例如 Challenge v1. 1 与 Challenge v1.0 的复制或分配模式不匹配)然后抛出异常。
基本上,有没有人迁移了一个 NSEncoding 对象并遇到了类似的情况,你采用了什么技术来解决这个问题?
我考虑过的选项
到目前为止,我已经尝试在对象树中的 Challenge 上方插入一个 superclass,但无法使其运行。
此外,我考虑过使用两步迁移,即发布 v1.1,它解码旧格式中持续存在的挑战,并在准备中保留一种新类型的对象 NewChallenge对于 v1.2 - 这对我来说似乎过于复杂(考虑到我只想添加两个属性)。
我考虑过扩展 Challenge 并在子 class 中存在属性,但这将意味着更改大量代码,这些代码期望看到 Challenge 对象。
如有任何见解,我们将不胜感激。
非常感谢 Archiver 的原作者 Mike Mayo (@greenisus) 提供了线索...
事实证明,在解码过程中可以检查任何给定密钥是否存在。 Archiver 项目使用下面的函数来解码对象;所以在它可以尝试解码一个不存在的密钥的地方检查编码器是否知道所述密钥 - 如果它不知道跳过带有 continue 子句的 for 循环的迭代。
- (void) autoDecode:(NSCoder *)coder
{
NSDictionary *properties = [self properties];
for (NSString *key in properties)
{
if (![coder containsValueForKey:key]) {
continue;
}
NSString *capitalizedKey = [key stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[key substringToIndex:1] capitalizedString]];
NSString *selectorString = [NSString stringWithFormat:@"set%@:", capitalizedKey];
SEL selector = NSSelectorFromString(selectorString);
NSMethodSignature *signature = [self methodSignatureForSelector:selector];
if (!signature) {
continue;
}
...
在我的例子中,编码对象在尝试解码哈希和描述时也会导致崩溃,因此需要第二个 continue 子句。
我正在使用 Archiver 的一个版本,运行 遇到了问题。
在我项目的先前版本中,class、Challenge 被序列化到磁盘
//v1.0
@interface Challenge : NSObject<NSCoding>
{
...
@property (nonatomic,strong) NSString *challengeId;
@property (nonatomic,strong) NSString *title;
@property (nonatomic) BOOL isCompleted;
...
}
现在,在应用程序的 1.1 版中,希望通过添加两个新的@properties 来更改 Challenge 对象。
//v1.1
@interface Challenge : NSObject<NSCoding>
{
...
@property (nonatomic,strong) NSString *challengeId;
@property (nonatomic,strong) NSString *title;
@property (nonatomic) BOOL isCompleted;
...
@property (nonatomic) BOOL isActive;
@property (nonatomic) NSInteger completeCount;
}
我的问题是,当 Archiver 尝试解码 Challenge 对象时,因为存在两个新属性(例如 Challenge v1. 1 与 Challenge v1.0 的复制或分配模式不匹配)然后抛出异常。
基本上,有没有人迁移了一个 NSEncoding 对象并遇到了类似的情况,你采用了什么技术来解决这个问题?
我考虑过的选项
到目前为止,我已经尝试在对象树中的 Challenge 上方插入一个 superclass,但无法使其运行。
此外,我考虑过使用两步迁移,即发布 v1.1,它解码旧格式中持续存在的挑战,并在准备中保留一种新类型的对象 NewChallenge对于 v1.2 - 这对我来说似乎过于复杂(考虑到我只想添加两个属性)。
我考虑过扩展 Challenge 并在子 class 中存在属性,但这将意味着更改大量代码,这些代码期望看到 Challenge 对象。
如有任何见解,我们将不胜感激。
非常感谢 Archiver 的原作者 Mike Mayo (@greenisus) 提供了线索...
事实证明,在解码过程中可以检查任何给定密钥是否存在。 Archiver 项目使用下面的函数来解码对象;所以在它可以尝试解码一个不存在的密钥的地方检查编码器是否知道所述密钥 - 如果它不知道跳过带有 continue 子句的 for 循环的迭代。
- (void) autoDecode:(NSCoder *)coder
{
NSDictionary *properties = [self properties];
for (NSString *key in properties)
{
if (![coder containsValueForKey:key]) {
continue;
}
NSString *capitalizedKey = [key stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[key substringToIndex:1] capitalizedString]];
NSString *selectorString = [NSString stringWithFormat:@"set%@:", capitalizedKey];
SEL selector = NSSelectorFromString(selectorString);
NSMethodSignature *signature = [self methodSignatureForSelector:selector];
if (!signature) {
continue;
}
...
在我的例子中,编码对象在尝试解码哈希和描述时也会导致崩溃,因此需要第二个 continue 子句。