NSKeyedArchiver并在目标之间共享自定义类 [英] NSKeyedArchiver and sharing a custom class between targets
问题描述
我的应用程序使用自定义类作为其数据模型:
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无法正确解码对象,因此我使用了此答案,并在类定义之前添加@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
的委托,并提供一个 unarchiver(_:cannotDecodeObjectOfClassName:originalClasses:)
,但这在这种情况下可能会过大.
请记住,这适用于向前迁移旧数据.如果您有新版本的应用程序需要将数据发送到旧版本的应用程序,则在存档方面,您需要做的事情与之类似-继续用 如果您有向后兼容性问题,那么很遗憾,只要有旧版本应用程序的用户,就可能需要继续使用旧名称. My app uses a custom class as its data model: I have just created a Today extension and need to access the user’s data from it, so I use NSCoding to persist my data in both the app container and the shared container. These are the save and load functions in the main app: I encountered the problem of class namespacing where the NSKeyedUnarchiver in my Today extension could not decode the object properly, so I used this answer and added This solved the problem perfectly. However, this will be version 1.3 of my app, and it seems this breaks the unarchiving process for pre-existing data (as I thought it might). What is the best way to handle this scenario, as if I just make this change, the new version of the app will crash for existing users! I cannot find any other answers about this, and I am not sure that the Any help would be gratefully received. Thanks. This is exactly the use case for Alternatively, you can provide a delegate conforming to Keep in mind that this works for migrating old data forward. If you have newer versions of the app that need to send data to old versions of the app, what you'll need to do is similar on the archive side — keep encoding the new class with the old name with If you have this backwards compatibility issue, then unfortunately, it's likely you'll need to keep using the old name as long as there are users of the old version of the app. 这篇关于NSKeyedArchiver并在目标之间共享自定义类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!class Drug: NSObject, NSCoding {
// Properties, methods etc...
}
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]
}
@objc
before the class definition:@objc(Drug)
class Drug: NSObject, NSCoding {
// Properties, methods etc...
}
NSKeyedArchiver.setClass()
method is relevant, nor am I sure where to use it.NSKeyedUnarchiver.setClass(_:forClassName:)
— you can migrate old classes forward by associating the current classes for their old names:let unarchiver = NSKeyedUnarchiver(...)
unarchiver.setClass(Drug.self, forClassName: "myApp.Drug")
// unarchive as appropriate
NSKeyedUnarchiverDelegate
and providing a unarchiver(_:cannotDecodeObjectOfClassName:originalClasses:)
, but that's likely overkill for this scenario.
NSKeyedArchiver.setClassName(_:for:)
:let archiver = NSKeyedArchiver(...)
archiver.setClassName("myApp.Drug", for: Drug.self)
// archive as appropriate