In my application, a NSDocument
subclass mission-critical hardware – users really don’t want to close a document by accident! So, I’ve implemented canCloseDocumentWithDelegate…
to show an NSAlert
and ask before closing.
I am now trying to implement this same thing in an application written in Swift.
Since the answer comes asynchronously, the “should close” result is passed to a callback on a delegate, and not simply returned. In the documentation for -canCloseDocumentWithDelegate:shouldCloseSelector:contextInfo:
, it says:
The shouldCloseSelector callback method should have the following signature:
- (void)document:(NSDocument *)doc shouldClose:(BOOL)shouldClose contextInfo:(void *)contextInfo
So, as there’s 3 arguments of different types, I cannot use the simple performSelector:withObject:
style methods – you have to use NSInvocation. Note that the delegate is of type id
, and the signature above does not appear in any formal protocol – you can’t simply call the method normally. (See this mailing list post for example of how this should be done)
Now, the issue is, NSInvocation is not allowed in Swift! See Swift blog “What Happened to NSMethodSignature”:
Bringing the Cocoa frameworks to Swift gave us a unique opportunity to look at our APIs with a fresh perspective. We found classes that we didn't feel fit with the goals of Swift, most often due to the priority we give to safety. For instance, some classes related to dynamic method invocation are not exposed in Swift, namely
NSInvocation
andNSMethodSignature
.
That sounds like a good thing, but falls down when a simple NSDocument
API requires NSInvocation still! The real solution to this whole problem would be for Apple to introduce a new canCloseDocument…
API using a block callback. But until that happens, what’s the best solution?