ios - NSKeyedArchiver 并在目标之间共享自定义类

标签 ios swift ios-app-extension nskeyedarchiver nskeyedunarchiver

我的应用使用自定义类作为其数据模型:

class Drug: NSObject, NSCoding {
    // Properties, methods etc...
}

我刚刚创建了一个 Today 扩展,需要从中访问用户的数据,所以我使用 NSCoding 将我的数据保存在应用程序容器和共享容器中。这些是主应用程序中的保存和加载功能:

func saveDrugs() {
    // Save to app container
    let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(drugs, toFile: Drug.ArchiveURL.path)
    if isSuccessfulSave {
        print("Drugs successfully saved locally")
    } else {
        print("Error saving drugs locally")
    }

    // Save to shared container for extension
    let isSuccessfulSaveToSharedContainer = NSKeyedArchiver.archiveRootObject(drugs, toFile: Drug.SharedArchiveURL.path)
    if isSuccessfulSaveToSharedContainer {
        print("Drugs successfully saved to shared container")
    } else {
        print("Error saving drugs to shared container")
    }
}

func loadDrugs() -> [Drug]? {
    return NSKeyedUnarchiver.unarchiveObject(withFile: Drug.ArchiveURL.path) as? [Drug]
}

我遇到了类命名空间问题,我的 Today 扩展中的 NSKeyedUnarchiver 无法正确解码对象,所以我使用了 this answer并在类定义前添加了 @objc:

@objc(Drug)
class Drug: NSObject, NSCoding {
    // Properties, methods etc...
}

完美解决了这个问题。但是,这将是我的应用程序的 1.3 版,这似乎打破了预先存在的数据的取消存档过程(正如我所想的那样)。

处理这种情况的最佳方法是什么,如果我只是进行此更改,新版本的应用程序将对现有用户崩溃!

我找不到关于此的任何其他答案,而且我不确定 NSKeyedArchiver.setClass() 方法是否相关,也不确定在哪里使用它。

如有任何帮助,我们将不胜感激。谢谢。

最佳答案

这正是 NSKeyedUnarchiver.setClass(_:forClassName:) 的用例— 您可以通过关联当前类的旧名称来向前迁移旧类:

let unarchiver = NSKeyedUnarchiver(...)
unarchiver.setClass(Drug.self, forClassName: "myApp.Drug")
// unarchive as appropriate

或者,您可以提供一个符合 NSKeyedUnarchiverDelegate 的委托(delegate)并提供 unarchiver(_:cannotDecodeObjectOfClassName:originalClasses:) ,但对于这种情况,这可能有点矫枉过正。


请记住,这适用于向前迁移旧数据。如果您有较新版本的应用程序需要将数据发送到旧版本的应用程序,那么您需要在存档端做的事情是类似的——继续使用 NSKeyedArchiver.setClassName(_:for:) 的旧名称对新类进行编码。 :

let archiver = NSKeyedArchiver(...)
archiver.setClassName("myApp.Drug", for: Drug.self)
// archive as appropriate

如果您遇到此向后兼容性问题,那么不幸的是,只要有旧版应用的用户,您就可能需要继续使用旧名称。

关于ios - NSKeyedArchiver 并在目标之间共享自定义类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48583761/

相关文章:

ios - react native : How to select the next TextInput after pressing the "next" keyboard button?

ios - Swift - 无法将函数转换为泛型

ios - 无法使用类型为 '[NSObject : Any]' 的索引下标类型为 'String' 的值

ios - 如何更改 MusicTrack 的乐器?

ios - swift - 根据对象的可选 bool 属性对对象数组进行排序,而无需强制展开

ios - 在prepareForSegue之后文本未完全通过(swift 3)

ios - 实时使用 NSTimer - Swift

ios - 在 Today Extensions (iOS 8) 上保存和加载数据

ios - 键盘扩展 : Is it possible to inherit features and UI from the stock iOS keyboard?

ios - 在 App 扩展中集成 Parse