【问题标题】:How to migrate an object which has been persisted with NSKeyedArchiver?如何迁移已使用 NSKeyedArchiver 持久化的对象?
【发布时间】:2015-01-28 16:26:17
【问题描述】:

我使用的是 Archiver 版本,但遇到了问题。

在我的项目的以前版本中,一个类 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 与 copy 或 alloc 不匹配Challenge v1.0 的模式)然后抛出异常。

基本上,有没有人迁移了一个 NSEncoding 对象并遇到了类似的情况,您采用了哪些技术来解决这个问题?

我考虑过的选项

到目前为止,我已尝试在对象树中的 Challenge 上方插入一个超类,但无法使其发挥作用。

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

我考虑过扩展 Challenge 并让属性存在于子类中,但这意味着要更改大量期望看到 Challenge 对象的代码。

任何见解将不胜感激。

【问题讨论】:

    标签: ios migration nscoding nskeyedarchiver object-persistence


    【解决方案1】:

    非常感谢 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 子句。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-10
      • 2011-11-28
      • 2013-09-05
      • 1970-01-01
      • 2014-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多