Reputation: 1014
I am using Core Data for persistent storage and I am getting the error listed below. I have looked up the message and I know it has something to do with the fact that I am using the transformable and a custom class. Despite my research I am not sure how to fix it. My attempt at conforming to the NSSecureCoding protocol failed miserably. I am posting my original code because I think it might be easier to try and solve the issue from scratch rather than trying to fix my poor attempt at NSSecureCoding. Thank you in advance! Any help is much appreciated.
'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
My Custom Class:
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))
}
}
View Controller:
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)
Upvotes: 4
Views: 2368
Reputation: 512
I haven't run this code, but it should work.
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)
}
}
@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)
}
}
// 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
}()
For more details, you can read this or this article.
Upvotes: 4