如何迁移使用NSKeyedArchiver持久化的对象?

4

我正在使用一个版本的 Archiver,并遇到了一个问题。

在我的项目的早期版本中,一个名为 Challenge 的类被序列化到磁盘上。

//v1.0
@interface Challenge : NSObject<NSCoding>
{
  ...
  @property (nonatomic,strong) NSString *challengeId;
  @property (nonatomic,strong) NSString *title;
  @property (nonatomic) BOOL isCompleted;
  ...
}

现在,在应用程序的1.1版本中,希望通过添加两个新的@属性来更改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,但无法使其正常工作。

此外,我考虑使用两步迁移,即发布v1.1,以旧格式解码持久化的挑战,并准备一种新类型的对象NewChallenge以备v1.2使用 - 这对我来说似乎过于复杂(考虑到我只想添加两个属性)。

我考虑扩展Challenge,并使属性存在于子类中,但这将意味着更改许多代码,这些代码期望看到一个Challenge对象。

任何见解都将不胜感激。

1个回答

4
非常感谢Archiver的原作者Mike Mayo (@greenisus)提供了线索,帮助我们解决了问题...
事实证明,在解码过程中可以检查任何给定键的存在性。 Archiver项目使用下面的函数来解码对象; 因此,在它尝试解码不存在的键的时候,需要检查编码器是否知道该键 - 如果不知道,则使用continue语句跳过循环的该次迭代。
- (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"子句。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接