Thank you for your kind assistance, The Eskimo. Your unarchivedObject(ofClasses:from:) doesn't even include NSDictionary, NSArray, NSString? The unarchivedObject guy is quite confusing.
I have minimized my work like the following to see how the guy works.
import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func saveClicked(_ sender: NSButton) {
showSavePanel()
}
@IBAction func openClicked(_ sender: NSButton) {
showOpenPanel()
}
func showSavePanel() {
let panel: NSSavePanel = NSSavePanel()
...
if (panel.runModal().rawValue == NSApplication.ModalResponse.cancel.rawValue) {
return
} else {
showSavePanelNext(fileURL: panel.url!)
}
}
func showSavePanelNext(fileURL: URL) {
let codeModel = CodeModel2(identifier: UUID().uuidString, highlightIndex: 1)
NSKeyedArchiver.setClassName("CodeModel2", for: CodeModel2.self)
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: codeModel, requiringSecureCoding: false)
try data.write(to: fileURL, options: .atomicWrite)
} catch {
print("Error: \(error.localizedDescription)")
}
}
func showOpenPanel() {
let panel = NSOpenPanel()
...
if (panel.runModal().rawValue == NSApplication.ModalResponse.cancel.rawValue) {
return
} else {
showOpenPanelNext(fileURL: panel.url!)
}
}
func showOpenPanelNext(fileURL: URL) {
do {
NSKeyedUnarchiver.setClass(CodeModel2.self, forClassName: "CodeModel2")
let data = try! Data(contentsOf: fileURL)
if let dict = try? NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSDictionary.self, NSString.self, CodeModel2.self], from: data) {
if let model = dict as? CodeModel2 {
let id = model.identifier
print("**** \(id)")
}
} else {
print("What!?")
}
}
}
}
class CodeModel2: NSObject, NSSecureCoding {
class var supportsSecureCoding: Bool { true }
let identifier: String
let highlightIndex: Int
init(identifier: String, highlightIndex: Int) {
self.identifier = identifier
self.highlightIndex = highlightIndex
}
required init(coder decoder: NSCoder) {
self.identifier = decoder.decodeObject(forKey: "identifier") as! String
self.highlightIndex = decoder.decodeInteger(forKey: "highlightIndex")
}
func encode(with coder: NSCoder) {
coder.encode(identifier, forKey: "identifier")
coder.encode(highlightIndex, forKey: "highlightIndex")
}
}
It's a simple example, and it works. The following doesn't. dict doesn't return a value.
import Cocoa
class ViewController: NSViewController {
func showSavePanelNext(fileURL: URL) {
let codeDataModel = CodeDataModel(lastComponent: "hello.png", data: Data("World!".utf8))
let codeModel = CodeReadModel(identifier: UUID().uuidString, highlightIndex: 2, codeDataModels: [codeDataModel])
NSKeyedArchiver.setClassName("CodeReadModel", for: CodeReadModel.self)
NSKeyedArchiver.setClassName("CodeDataModel", for: CodeDataModel.self)
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: codeModel, requiringSecureCoding: false)
try data.write(to: fileURL, options: .atomicWrite)
} catch {
print("Error: \(error.localizedDescription)")
}
}
func showOpenPanel() {
let panel = NSOpenPanel()
panel.allowsMultipleSelection = false
panel.canChooseDirectories = false
panel.canCreateDirectories = false
panel.canChooseFiles = true
panel.allowedContentTypes = [.text]
panel.title = "Open me!"
panel.message = ""
//panel.directoryURL = NSURL.fileURL(withPath: openPath)
if (panel.runModal().rawValue == NSApplication.ModalResponse.cancel.rawValue) {
return
} else {
showOpenPanelNext(fileURL: panel.url!)
}
}
func showOpenPanelNext(fileURL: URL) {
do {
NSKeyedUnarchiver.setClass(CodeReadModel.self, forClassName: "CodeReadModel")
NSKeyedUnarchiver.setClass(CodeDataModel.self, forClassName: "CodeDataModel")
let data = try! Data(contentsOf: fileURL)
if let dict = try? NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSDictionary.self, NSArray.self, NSString.self, CodeReadModel.self, CodeDataModel.self], from: data) {
if let model = dict as? CodeReadModel {
let id = model.identifier
print("**** \(id)")
}
} else {
print("What!?")
}
}
}
}
class CodeDataModel: NSObject, NSSecureCoding {
class var supportsSecureCoding: Bool { true }
let lastComponent: String
let data: Data
init(lastComponent: String, data: Data) {
self.lastComponent = lastComponent
self.data = data
}
required init(coder decoder: NSCoder) {
self.lastComponent = decoder.decodeObject(forKey: "lastComponent") as! String
self.data = decoder.decodeObject(forKey: "data") as! Data
}
func encode(with coder: NSCoder) {
coder.encode(lastComponent, forKey: "lastComponent")
coder.encode(data, forKey: "data")
}
}
class CodeReadModel: NSObject, NSSecureCoding {
class var supportsSecureCoding: Bool { true }
let identifier: String
let highlightIndex: Int
let codeDataModels: [CodeDataModel]
init(identifier: String, highlightIndex: Int, codeDataModels: [CodeDataModel]) {
self.identifier = identifier
self.highlightIndex = highlightIndex
self.codeDataModels = codeDataModels
}
required init(coder decoder: NSCoder) {
self.identifier = decoder.decodeObject(forKey: "identifier") as! String
self.highlightIndex = decoder.decodeInteger(forKey: "highlightIndex")
self.codeDataModels = decoder.decodeObject(forKey: "codeDataModels") as! [CodeDataModel]
}
func encode(with coder: NSCoder) {
coder.encode(identifier, forKey: "identifier")
coder.encode(highlightIndex, forKey: "highlightIndex")
coder.encode(codeDataModels, forKey: "codeDataModels")
}
}