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 (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to