I'm having troubles encoding/decoding an array of Data (basically file bookmarks) in NSCoder protocol.
Here's what I'm trying to do:
class ClosedFiles: NSCoder {
static var supportsSecureCoding = true
let bookmarks: [Data]
init?(with coder: NSCoder) {
if let bm = coder.decodeObject() as? [Data] {
bookmarks = bm
} else {
return nil
}
}
init(bookmarks: [Data]) {
self.bookmarks = bookmarks
}
func encode(with coder: NSCoder) {
coder.encodeRootObject(bookmarks)
}
}
I encode this object in my app delegate:
func application(_ app: NSApplication, willEncodeRestorableState coder: NSCoder) {
coder.encodeRootObject(ClosedFiles(bookmarks: closedFiles))
}
This throws the error in runtime:
Ignoring exception: This decoder will only decode classes that adopt NSSecureCoding. Class '_TtCC7MyApp11AppDelegate11ClosedFiles' does not adopt it.
I'm following the apple's doc to conform to NSSecure, but it doesn't seem to work. I tried a few other method, but nothing seems working: coder.encode(), coder.encodeConditionalObject, and whatever else I found.
Any thought what I'm doing wrong?
You need a lot of changes for your class to support NSCoding
(actually NSSecureCoding
.
NSObject
NSSecureCoding
init(coder:)
initializersupportsSecureCoding
property needs to be staticNSCoding
methods need to be written correctly to support secure coding.Here's your class with all of the changes.
class ClosedFiles: NSObject, NSSecureCoding {
let bookmarks: [Data]
required init?(coder: NSCoder) {
if let bm = coder.decodeArrayOfObjects(ofClass: NSData.self, forKey: "bookmarks") as? [Data] {
bookmarks = bm
} else {
return nil
}
}
init(bookmarks: [Data]) {
self.bookmarks = bookmarks
}
func encode(with coder: NSCoder) {
coder.encode(bookmarks as [NSData], forKey: "bookmarks")
}
static var supportsSecureCoding: Bool {
return true
}
}
I tested these changes in a Playground using the following code:
do {
let closed = ClosedFiles(bookmarks: [ "Hello".data(using: .utf8)!, "There".data(using: .utf8)! ])
let data = try NSKeyedArchiver.archivedData(withRootObject: closed, requiringSecureCoding: true)
let dupe = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [ClosedFiles.self, NSArray.self, NSData.self], from: data) as! ClosedFiles
let str1 = String(data: dupe.bookmarks[0], encoding: .utf8)!
print(str1)
} catch {
print(error)
}
This gives back the expected results.