I am trying with NSDocument based application first time. (Xcode 9.2, Swift 4, macOS 10.12 Sierra, and Cocoa/AppKit)
I would like to know proper way to implement closing Document with No autosaving. Would you please show me the best practice of closing NSDocument?
When user is trying to close document, following NSDocument method is called.
canClose(withDelegate:shouldClose:contextInfo:)
I debug the parameters and find followimng:
delegate = MyApp.Document
shouldCloseSelector = _something:didSomething:soContinue:
contextInfo = libsystem_blocks.dylib `_NSConcreteMallocBlock
Apparently such selector is not available, so I think this can be altered here like:
override func canClose(withDelegate delegate: Any,
shouldClose shouldCloseSelector: Selector?,
contextInfo: UnsafeMutableRawPointer?) {
let delegate : Any = self
let shouldCloseSelector : Selector = #selector(Document.document(_:shouldClose:contextInfo:))
super.canClose(withDelegate: delegate, shouldClose: shouldCloseSelector, contextInfo: contextInfo)
}
@objc func document(_ document : NSDocument, shouldClose flag : Bool,
contextInfo: UnsafeMutableRawPointer?) {
if document === self, flag {
self.cleanup() // my cleanup method
self.close() // NSDocument.close()
}
}
deinit {
Swift.print(#function, #line)
}
It seems to work, but I guess this is not proper way, because of ignroing original parameters (Selector/contextInfo).
I have found solution. I hope this would help someone.
private var closingBlock : ((Bool) -> Void)? = nil
override func canClose(withDelegate delegate: Any,
shouldClose shouldCloseSelector: Selector?,
contextInfo: UnsafeMutableRawPointer?) {
let obj : AnyObject = delegate as AnyObject
let Class : AnyClass = object_getClass(delegate)!
let method = class_getMethodImplementation(Class, shouldCloseSelector!)
typealias signature =
@convention(c) (AnyObject, Selector, AnyObject, Bool, UnsafeMutableRawPointer?) -> Void
let function = unsafeBitCast(method, to: signature.self)
self.closingBlock = {[unowned obj, shouldCloseSelector, contextInfo] (flag) -> Void in
function(obj, shouldCloseSelector!, self, flag, contextInfo)
}
let delegate : Any = self
let shouldCloseSelector : Selector = #selector(Document.document(_:shouldClose:contextInfo:))
super.canClose(withDelegate: delegate, shouldClose: shouldCloseSelector, contextInfo: contextInfo)
}
@objc func document(_ document : NSDocument, shouldClose flag : Bool,
contextInfo: UnsafeMutableRawPointer?) {
if flag {
self.cleanup() // my cleanup method
}
self.closingBlock?(flag)
self.closingBlock = nil
}
override func close() {
Swift.print(#function, #line, #file)
super.close()
}
deinit {
Swift.print(#function, #line, #file)
}
https://developer.apple.com/library/content/releasenotes/AppKit/RN-AppKitOlderNotes/
Advice for Overriders of Methods that Follow the delegate:didSomethingSelector:contextInfo: Pattern
https://github.com/DouglasHeriot/canCloseDocumentWithDelegate/blob/master/canCloseDocumentWithDelegate/Document.swift
Shows how to implement the NSDocument method -canCloseDocumentWithDelegate:shouldCloseSelector:contextInfo: using Swift. Must use Objective-C to perform an NSInvocation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With