NSDocument -canCloseDocumentWithDelegate::: not called when terminating
NSDocument -canCloseDocumentWithDelegate::: not called when terminating
- Subject: NSDocument -canCloseDocumentWithDelegate::: not called when terminating
- From: Jonathan Mitchell <email@hidden>
- Date: Wed, 30 Aug 2017 14:18:44 +0100
This is one from the archives:
https://lists.apple.com/archives/cocoa-dev/2012/Jul/msg00740.html
In short NSDocument -canCloseDocumentWithDelegate::: gets called on documents
when closing the document window but only for dirty documents when closing the
app via NSApp -terminate: (i.e.: the application Quit menu item).
My documents have a lot of variable user cancellable activity that must run
prior to document closure regardless of whether the document is dirty or not.
Trying to fudge the document dirty flag as and when required just sounds like a
maintenance headache.
My solution is to run a termination preflight that processes my clean documents
prior to allowing actual termination,
My experience is that intervening in the NSDocument machinery at critical
points can be a recipe for disaster if things are not quite right.
If anyone has attempted this in the past comments would be appreciated.
NSApplication subclass
==================
- (void)terminate:(id)sender
{
// The logic here is quite complex
//
https://developer.apple.com/documentation/appkit/nsapplication/1428417-terminate?language=objc
// The receiver calls NSDocumentController to check if documents can be
closed.
// If those methods don't handle their callbacks accurately then then this
method never returns (even in termination does not occur)
// and I think we end up in an inner run loop.
//
// If the termination process succeeds then this method does not return.
// If the termination process is cancelled then this method does return;
self.isTerminating = YES;
// preflight
// see https://lists.apple.com/archives/cocoa-dev/2012/Jul/msg00740.html
// when we call terminate: non edited document instances do not get
processed like diirty docs hence the preflight
BOOL preflight = [[BPDocumentController sharedDocumentController]
preflightCloseAllDocumentsOnApplicationTerminate];
if (preflight) {
[super terminate:sender];
}
self.isTerminating = NO;
}
NSDocumentController subclass
=========================
- (BOOL)preflightCloseAllDocumentsOnApplicationTerminate
{
// see https://lists.apple.com/archives/cocoa-dev/2012/Jul/msg00740.html
// when we call NSApp -terminate: non edited document instances do not get
processed like dirty docs hence this preflight
BOOL success = YES;
// this method is only available if within NSApp -terminate:
BOOL appTerminating = [(BPApplication *)NSApp isTerminating];
if (!appTerminating) {
return NO;
}
// we need to preflight non edited documents
NSArray *cleanDocuments = [self.documents linq_where:^BOOL(BPDocument * doc)
{
return !doc.isDocumentEdited;
}];
for (NSDocument *doc in cleanDocuments) {
self.cleanDocumentTerminateInfo = nil;
// this method is called by default on dirty docs but in order to retain
our sanity and ensure that the doc close logic
// is called in all situations we call it here too
[doc canCloseDocumentWithDelegate:self
shouldCloseSelector:@selector(onTerminateCleanDocument:shouldClose:contextInfo:)
contextInfo:NULL];
// process events until our close selector gets called
while (!self.cleanDocumentTerminateInfo) {
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES];
[NSApp sendEvent:event];
}
success = [self.cleanDocumentTerminateInfo[@"shouldClose"] boolValue];
if (!success) {
break;
}
}
self.cleanDocumentTerminateInfo = nil;
return success;
}
- (void)onTerminateCleanDocument:(NSDocument *)doc
shouldClose:(BOOL)shouldClose contextInfo:(void *)contextInfo
{
self.cleanDocumentTerminateInfo = @{@"document" : doc, @"shouldClose" :
@(shouldClose)};
}
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden