I experience an odd behaviour regarding saving an NSPersistentDocument. I can create a new document which is autosaved without an issue. But when I save it write(to: ofTyp
Another, simpler workaround:
The following code has a bug. Please refer to the bug fixed version cited below.
extension NSPersistentStoreCoordinator {
@objc func x_migratePersistentStore(_ store: NSPersistentStore, to URL: URL, options: [AnyHashable : Any]? = nil, withType storeType: String) throws -> NSPersistentStore {
var opt: [AnyHashable : Any] = options ?? [:]
if #available(OSX 10.13, *) {
opt[NSBinaryStoreSecureDecodingClasses] = NSSet(array: [ NSColor.self ])
}
return try x_migratePersistentStore(store, to: URL, options: opt, withType: storeType)
}
}
class Document: NSPersistentDocument {
override init() {
super.init()
let s1 = #selector(NSPersistentStoreCoordinator.migratePersistentStore(_:to:options:withType:))
let s2 = #selector(NSPersistentStoreCoordinator.x_migratePersistentStore(_:to:options:withType:))
let m1 = class_getInstanceMethod(NSPersistentStoreCoordinator.self, s1)!
let m2 = class_getInstanceMethod(NSPersistentStoreCoordinator.self, s2)!
method_exchangeImplementations(m1, m2)
}
override func configurePersistentStoreCoordinator(for url: URL, ofType fileType: String, modelConfiguration configuration: String?, storeOptions: [String : Any]? = nil) throws {
// keep yours
}
}
Added:
This workaround is going to be a practical solution until they enhance NSPersistentDocument.write(to...)
to take into account of options or they implement other means to handle options. Those options will be given to NSPersistentStoreCoordinator.migratePersistentStore(...)
and then be used to instantiate NSPersistentStore
.
Bug Fixed Version:
There was a bug in the preceding workaround. Opening document files, creating new files, making changes, waiting for thirty second to the document being auto-saved, closing them, and/or save-as-ing them randomly would cause the initial error. Reported by Wizard of Kneup.
Here is a fixed version using singleton to make sure swizzling is applied only once.
extension NSPersistentStoreCoordinator {
@objc func x_migratePersistentStore(_ store: NSPersistentStore, to URL: URL, options: [AnyHashable : Any]? = nil, withType storeType: String) throws -> NSPersistentStore {
var opt: [AnyHashable : Any] = options ?? [:]
if #available(OSX 10.13, *) {
opt[NSBinaryStoreSecureDecodingClasses] = NSSet(array: [ NSColor.self ])
}
return try x_migratePersistentStore(store, to: URL, options: opt, withType: storeType)
}
class MigratePersistentStoreInitializer {
init() {
let s1 = #selector(NSPersistentStoreCoordinator.migratePersistentStore(_:to:options:withType:))
let s2 = #selector(NSPersistentStoreCoordinator.x_migratePersistentStore(_:to:options:withType:))
let m1 = class_getInstanceMethod(NSPersistentStoreCoordinator.self, s1)!
let m2 = class_getInstanceMethod(NSPersistentStoreCoordinator.self, s2)!
method_exchangeImplementations(m1, m2)
}
static let singlton = MigratePersistentStoreInitializer() // Lazy Stored Property
}
}
class Document: NSPersistentDocument {
override init() {
super.init()
let _ = NSPersistentStoreCoordinator.MigratePersistentStoreInitializer.singlton
}
override func configurePersistentStoreCoordinator(for url: URL, ofType fileType: String, modelConfiguration configuration: String?, storeOptions: [String : Any]? = nil) throws {
// keep yours
}
}
References: