NSKeyedArchiver 并在目标之间共享自定义 class
NSKeyedArchiver and sharing a custom class between targets
我的应用使用自定义 class 作为其数据模型:
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]
}
我遇到了 class 命名空间问题,我的 Today 扩展中的 NSKeyedUnarchiver 无法正确解码对象,所以我使用了 并在 [=31 之前添加了 @objc
=]定义:
@objc(Drug)
class Drug: NSObject, NSCoding {
// Properties, methods etc...
}
完美解决了这个问题。但是,这将是我的应用程序的 1.3 版,这似乎打破了预先存在的数据的取消存档过程(正如我所想的那样)。
处理这种情况的最佳方法是什么,如果我只是进行此更改,新版本的应用程序将对现有用户崩溃!
我找不到关于此的任何其他答案,我不确定 NSKeyedArchiver.setClass()
方法是否相关,也不确定在哪里使用它。
如有任何帮助,我们将不胜感激。谢谢。
这正是 NSKeyedUnarchiver.setClass(_:forClassName:)
的用例 — 您可以通过将当前 classes 与其旧名称相关联来向前迁移旧 classes:
let unarchiver = NSKeyedUnarchiver(...)
unarchiver.setClass(Drug.self, forClassName: "myApp.Drug")
// unarchive as appropriate
或者,您可以提供一个符合 NSKeyedUnarchiverDelegate
and providing a unarchiver(_:cannotDecodeObjectOfClassName:originalClasses:)
的委托,但这对于这种情况可能有点过分了。
请记住,这适用于向前迁移旧数据。如果您有较新版本的应用程序需要将数据发送到旧版本的应用程序,则您需要在存档端做类似的事情——继续使用旧名称 [=] 对新 class 进行编码18=]:
let archiver = NSKeyedArchiver(...)
archiver.setClassName("myApp.Drug", for: Drug.self)
// archive as appropriate
如果您遇到此向后兼容性问题,那么不幸的是,只要有旧版应用的用户,您就可能需要继续使用旧名称。
我的应用使用自定义 class 作为其数据模型:
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]
}
我遇到了 class 命名空间问题,我的 Today 扩展中的 NSKeyedUnarchiver 无法正确解码对象,所以我使用了 @objc
=]定义:
@objc(Drug)
class Drug: NSObject, NSCoding {
// Properties, methods etc...
}
完美解决了这个问题。但是,这将是我的应用程序的 1.3 版,这似乎打破了预先存在的数据的取消存档过程(正如我所想的那样)。
处理这种情况的最佳方法是什么,如果我只是进行此更改,新版本的应用程序将对现有用户崩溃!
我找不到关于此的任何其他答案,我不确定 NSKeyedArchiver.setClass()
方法是否相关,也不确定在哪里使用它。
如有任何帮助,我们将不胜感激。谢谢。
这正是 NSKeyedUnarchiver.setClass(_:forClassName:)
的用例 — 您可以通过将当前 classes 与其旧名称相关联来向前迁移旧 classes:
let unarchiver = NSKeyedUnarchiver(...)
unarchiver.setClass(Drug.self, forClassName: "myApp.Drug")
// unarchive as appropriate
或者,您可以提供一个符合 NSKeyedUnarchiverDelegate
and providing a unarchiver(_:cannotDecodeObjectOfClassName:originalClasses:)
的委托,但这对于这种情况可能有点过分了。
请记住,这适用于向前迁移旧数据。如果您有较新版本的应用程序需要将数据发送到旧版本的应用程序,则您需要在存档端做类似的事情——继续使用旧名称 [=] 对新 class 进行编码18=]:
let archiver = NSKeyedArchiver(...)
archiver.setClassName("myApp.Drug", for: Drug.self)
// archive as appropriate
如果您遇到此向后兼容性问题,那么不幸的是,只要有旧版应用的用户,您就可能需要继续使用旧名称。