NSDocument saveDocumentWithDelegate deadlocked during App termination

  • How do I force *all* NSDocument dialogs to be handled SYNCHRONOUSLY?

    NSDocument continues to be a software maintenance nightmare.

    Asynchronous NSDocument dialogs should be the exception, not the rule, *especially* in these cases:

      NSApp knows its being asked to terminate.
      NSApp knows it hasn't finished loading.

    http://stackoverflow.com/questions/16360898/nsdocument-savedocumentwithdele
    gate-deadlocked-during-app-termination


    BEGIN EDIT: I *may* have found a solution that allows me to wait synchronously
    ------------------------------------------------------------------------
    Can anyone verify that this would be an "Apple approved" solution?

        static BOOL sWaitingForDidSaveModally = NO;
        BOOL gWaitingForDidSaveCallback = NO; // NSDocument dialog calls didSave: when done



        ...
          gWaitingForDidSaveCallback = true;
          [toDocument saveDocumentWithDelegate:self
                              didSaveSelector:@selector(document:didSave:contextInfo:)
                                  contextInfo:nil];
          if ( gWaitingForDidSaveCallback )
          {
              // first, dispatch any other potential alerts synchronously
              while ( gWaitingForDidSaveCallback && [NSApp modalWindow] )
                [NSApp runModalForWindow: [NSApp modalWindow]];

              if ( gWaitingForDidSaveCallback )
              {
                sWaitingForDidSaveModally = YES;
                [NSApp runModalForWindow: [NSApp mbWindow]]; // mbWindow is our big (singleton) window
                sWaitingForDidSaveModally = NO;
              }
          }
        ...

        - (void)document:(NSDocument *)doc didSave:(BOOL)didSave contextInfo:(void  *)contextInfo
        {
          [self recordLastSaveURL];
          gWaitingForDidSaveCallback = NO;
          if ( sWaitingForDidSaveModally )
              [NSApp stopModal];

        }
    END EDIT
    ------------------------------------------------------------------------

    I have to support Snow Leopard/Lion/ML

    App termination is an ugly process.
    When the user decides to quit, and the document has changes that need saving, I call this:

          gWaitingForDidSaveCallback = true;
          [toDocument saveDocumentWithDelegate:self
                              didSaveSelector:@selector(document:didSave:contextInfo:)
                                  contextInfo:nil];

    I *really really really* want this call to be synchronous, but in latest Lion, this hangs my app:

          while ( gWaitingForDidSaveCallback )
          {
              // didSave: callback clears sWaitingForDidSaveCallback
              // do my own synchronous wait for now
              [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceReferenceDate:0.05]];
          }

    My best guess for the hang is that the mouseDown: of a window close button
    is confusing the NSDocument.

    So now, I have to return, and pepper my apps main loop with unmaintainable state machine logic to prevent user from executing various dangerous hotkeys.

    Ok, so I grin and bear it, and run into yet another roadblock!

    In previous OS versions/SDKs, [NSApp modalWindow] would return a window when it
    was in this state.  Now it doesn't!  Grrrrr...
    NSDocument has no API to test when it is in this state!

    So, now there is no mechanism to globally check this state!
    I have to add yet another state variable to my state machine.

    Anyone have a cleaner solution for this problem that works in all OS versions and all present (and future) SDKs?
  • On Fri, May 3, 2013, at 01:32 PM, Keith Knauber wrote:
    > How do I force *all* NSDocument dialogs to be handled SYNCHRONOUSLY?

    You don't.

    >
    > NSDocument continues to be a software maintenance nightmare.

    I agree, but until Apple simplifies the API, correctly dealing with
    NSDocument will simply require a lot of learning.

    >
    > Asynchronous NSDocument dialogs should be the exception, not the rule,> *especially* in these cases:
    >
    > NSApp knows its being asked to terminate.
    > NSApp knows it hasn't finished loading.

    What case are you trying to handle here? NSApp can't be asked to
    terminate before it's finished loading; since the main thread is busy
    running code, neither the menu bar nor the AppleEvent handler can
    possibly handle the termination request.

    Did you mean to say you want to quit the app while _documents_ are still
    loading? If so, what does this have to do with synchronous dialogs?

    --Kyle Sluder
previous month may 2013 next month
MTWTFSS
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
Go to today