Search code examples
macoscocoansdocumentnspersistentdocument

NSDocumentController closeAllDocumentsWithDelegate does not call canCloseDocumentWithDelegate of my NSPersistentDocument subclass


According to Apple's docs, closeAllDocumentsWithDelegate (from NSDocumentController) should call canCloseDocumentWithDelegate of NSDocument for all open documents if you quit an application.

In my NSPersistentDocument-based app I need to override canCloseDocumentWithDelegate in order to warn the user in case a certain server functionality is still running when the document closes. This has nothing to do with any data changes. This works when the user closes a single document; I can present a sheet with the warning and let the user cancel the closing process.

However, my version of canCloseDocumentWithDelegate does not get called when the app is quit. What could be the reason for that?


Solution

  • According to Apple Developer Technical Support this is a known issue. I finally cut the automatic wiring of the app's quit menu item and handle it all by myself. I needed to make the server functionality information of the document available from the outside (in this example the state of optionButton) and added this function to the AppDelegate:

    - (IBAction)terminateGracefully:(id)sender {
        BOOL optionOn = FALSE;
        for (Document *doc in NSApp.orderedDocuments) {
            if (doc.optionButton.state == NSControlStateValueOn) {
                optionOn = TRUE;
            }
        }
    
        if (optionOn) {
            NSAlert *alert = [[NSAlert alloc] init];
            [alert setMessageText:@"Checkbox in some window is on"];
            [alert setInformativeText:@"Something is going on. If you close the app now, it will stop. Close anyway?\n"];
            [alert setAlertStyle:NSAlertStyleCritical];
            [alert addButtonWithTitle:@"Don't close"];
            [alert addButtonWithTitle:@"Close anyway"];
    
            NSModalResponse resp = [alert runModal];
    
            if (resp == NSAlertSecondButtonReturn) {
                // We really want to close
                [NSApp terminate:sender];
            }
    
        } else {
            [NSApp terminate:sender];
        }
    }
    

    Then I bound the app's quit menu item to terminateGracefully:

    Xcode binding