繁体   English   中英

如何在从 Objective-C 迁移到 Swift 时正确地将使用 NSKeyedArchiver 保存的旧数据迁移到新格式

[英]How to correctly migrate old data saved with NSKeyedArchiver into new format while migrating from Objective-C to Swift

该应用程序的旧版本具有符合NSCoding的 class(我们称之为OldItem ),用 Objective C 编写。 这个 class 有大约 20 个不同类型的属性:

@property (nonatomic) NSInteger x;

// ...

- (id)initWithCoder:(NSCoder *)coder {

    if (self = [super init])  {
        _x = [coder decodeIntegerForKey:@"x"];
        // all 20 fields are decoded in the similar way
    }

    return self;
}

- (void)encodeWithCoder:(NSCoder *)coder {
    [self.x encodeWithCoder:coder];
    // all 20 fields encoded in the similar way
}

它在另一个 class (我们称之为Controller )中用作数组:

@property (nonatomic, strong, nonnull) NSMutableArray<OldItem *> *items;

Controller还将项目缓存到磁盘,如下所示:

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.items];
[data writeToFile:@"myfile.txt" options:NSDataWritingFileProtectionComplete error:nil];

现在我需要将OldItem迁移到 Swift,而Controller只更改它处理的项目类型:

@property (nonatomic, strong, nonnull) NSMutableArray<NewItem *> *items; 

问题是:如何将旧版本的应用程序中保存在myfile.txt中的旧数据迁移到新版本中?

  • 理想情况下,新的 class 具有不同的名称,例如NewItem ,但我愿意保留旧名称,如果它显着简化了迁移。
  • 不在乎新版本是否会将数据保存到同一个文件中,或者读取旧文件一次,然后将数据移动到新文件中。
  • 对于这个问题,请忽略OldItemNewItem之间的任何差异。 将它们视为直接端口。
  • 显然NewItem仍应符合NSCoding标准,并且将NewItem读/写到文件中不是问题。

没有什么可以迁移的。 NSCoder 是 Cocoa 的东西,不是语言的东西; 无论您在 Objective C 或 Swift 中与它交谈,它的工作原理都是一样的。 只需将所有代码行逐行转换为 Swift 即可。 旧的存档数据继续正常工作,因为存档仍然是存档,编码器仍然是编码器。 Edit If the question is how to give your Swift class the old Objective C class's name so that the archive can be read into it, note that Objective C MyClass and Swift MyClass have different names because of Swift name mangling; 你不得不说

@objc(MyClass) class Whatever : NSObject {

看了一会,实际的解决办法是:

  1. 确保 NewItem class 中的public required init?(coder: NSCoder)正确地取消归档您想要从 OldItem 保留的所有字段。 例如枚举或数字类型转换可能需要特殊处理,即使您没有更改字段本身。

  2. 在取消归档之前,使用NSKeyedUnarchiver.setClass方法告诉NSKeyedUnarchiver应该使用 NewItem 代替 OldItem。

例子:

let archivedData = try Data(contentsOf: filePath)
NSKeyedUnarchiver.setClass(NewItem.self, forClassName: "OldItem")
let items = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(archivedData)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM