ios - 如何修复“NSKeyedUnarchiveFromData”不应用于取消归档并将在未来版本中删除的错误?
问题描述
我正在使用 Core Data 进行持久存储,我收到下面列出的错误。我查看了这条消息,我知道这与我使用可转换类和自定义类有关。尽管我进行了研究,但我不确定如何解决它。我尝试遵守 NSSecureCoding 协议失败了。我发布我的原始代码是因为我认为从头开始尝试解决问题可能比尝试修复我在 NSSecureCoding 上的糟糕尝试更容易。先感谢您!任何帮助深表感谢。
'NSKeyedUnarchiveFromData' 不应用于取消归档,并将在未来版本中删除
我的自定义类:
public class SelectedImages: NSObject, NSCoding {
public var images: [SelectedImage] = []
enum Key: String {
case images = "images"
}
init(images: [SelectedImage]) {
self.images = images
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(images, forKey: Key.images.rawValue)
}
public required convenience init?(coder aDecoder: NSCoder) {
let mImages = aDecoder.decodeObject(forKey: Key.images.rawValue) as! [SelectedImage]
self.init(images: mImages)
}
}
public class SelectedImage: NSObject, NSCoding {
public var location: Int = 0
public var duration: Int = 10
public var localIdentifier: String = ""
enum Key: String {
case location = "location"
case duration = "duration"
case localIdentifier = "localIdentifier"
}
init(location: Int, duration: Int, localIdentifier: String) {
self.location = location
self.duration = duration
self.localIdentifier = localIdentifier
}
public override init() {
super.init()
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(location, forKey: Key.location.rawValue)
aCoder.encode(duration, forKey: Key.duration.rawValue)
aCoder.encode(localIdentifier, forKey: Key.localIdentifier.rawValue)
}
public required convenience init?(coder aDecoder: NSCoder) {
let mlocation = aDecoder.decodeInt32(forKey: Key.location.rawValue)
let mduration = aDecoder.decodeInt32(forKey: Key.duration.rawValue)
let mlocalIdentifier = aDecoder.decodeObject(forKey: Key.localIdentifier.rawValue) as! String
self.init(location: Int(mlocation), duration:Int(mduration), localIdentifier:String(mlocalIdentifier))
}
}
视图控制器:
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let userEntity = NSEntityDescription.entity(forEntityName: "EntityTest", in: managedContext)!
let selectedImages = NSManagedObject(entity: userEntity, insertInto: managedContext) as! EntityTest
let mImages = SelectedImages(images: selectionArrays)
selectedImages.setValue(mImages, forKeyPath: "image")
do {
try managedContext.save()
print("Images saved to core data")
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
let newViewController = PickerTest6()
self.navigationController?.pushViewController(newViewController, animated: true)
解决方案
我没有运行此代码,但它应该可以工作。
- 对SelectedImage类进行更改。
public class SelectedImage: NSObject, NSSecureCoding { // Class must inherit from NSSecureCoding
public static var supportsSecureCoding: Bool = true // It's the required property
public var location: Int = 0
public var duration: Int = 10
public var localIdentifier: String = ""
private enum CodingKeys: String {
case location, duration, localIdentifier
}
public override init() {
super.init()
}
init(location: Int, duration: Int, localIdentifier: String) {
self.location = location
self.duration = duration
self.localIdentifier = localIdentifier
}
public required init?(coder: NSCoder) {
self.location = coder.decodeInteger(forKey: CodingKeys.location.rawValue)
self.duration = coder.decodeInteger(forKey: CodingKeys.duration.rawValue)
// Now instead of decodeObject(forKey:) you should use decodeObject(of: forKey:).
self.localIdentifier = coder.decodeObject(of: NSString.self, forKey: CodingKeys.localIdentifier.rawValue) as String? ?? ""
}
public func encode(with coder: NSCoder) {
coder.encode(location, forKey: CodingKeys.location.rawValue)
coder.encode(duration, forKey: CodingKeys.duration.rawValue)
coder.encode(localIdentifier, forKey: CodingKeys.localIdentifier.rawValue)
}
}
- 创建SelectedImageTransformer类。
@objc(SelectedImageTransformer)
final class SelectedImageTransformer: NSSecureUnarchiveFromDataTransformer {
static let name = NSValueTransformerName(rawValue: String(describing: SelectedImageTransformer.self))
override class var allowedTopLevelClasses: [AnyClass] {
return super.allowedTopLevelClasses + [SelectedImage.self]
}
public class func register() {
let transformer = SelectedImageTransformer()
ValueTransformer.setValueTransformer(transformer, forName: name)
}
}
- 按如下方式编辑 CoreData 模型。
- 在初始化持久容器之前调用AppDelegate中的 register 方法(如果您使用 UIKit)。
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
// Register the transformer
SelectedImageTransformer.register()
let container = NSPersistentContainer(name: "AppName")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
推荐阅读
- android - Recyclerview DiffUtil 项目更新
- gps - 如何在没有 GPS 帮助的情况下使用 SIM7600 GSM 模块获取位置(经纬度)?
- c# - 我可以避免在启动时使用 BuildServiceProvider 吗?
- javascript - How to insert a map into a popover - bootstrap
- r - 从 dplyr 中均匀分布的随机样本生成的相同值
- reactjs - 如何在 Gatsby 中实现 Three.js?
- ios - Authorize.net 支付网关 Charge a Credit Card API for iOS swift
- python - 无法通过 Django 的管理页面登录
- spring - 使用“@Scheduled”运行时 getThreadPoolExecutor().getQueue().size() 返回零
- c# - 如何在控制台窗口中使字符串变为粗体?