1

The problem: Attempting to display a window with text from applicationWillFinishLaunching will NOT draw itself if other processor-intensive non-UI code is immediately called.

Background: I have a helper app that when launched may or may not interact with the end user. While it is "deciding" if it needs to put up a window to ask user questions, there may be anywhere from 1 second to 10 seconds that elapse (after launch it's off in non-UI capable library code communicating over the internet).

So I wanted to be kind to the user and put up a "mini-alert"* window with "working, please wait...", prior to heading into that library code, which I will dismiss once that processing has elapsed.

It seems as if the app itself doesn't have time after launch to even draw this mini-alert (it's just an NSWindow, with an NSView, some text, and no buttons).

If after the library code returns and want to put up either an error alert or a query window for the user -- then at that point the mini-alert draws as expected. However, if I close the mini-alert (see below) and then put up an NSAlert -- the mini-alert doesn't have enough time to dismiss itself.

- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
    [NSApp activateIgnoringOtherApps:YES];

    briefAlertWindowController = [[NSWindowController alloc] initWithWindowNibName:@"BriefAlertWindow"];

    [[briefAlertWindowController window] center];
    [briefAlertWindowController showWindow:self ];
    [[briefAlertWindowController window] orderFront:self ];
    [[briefAlertWindowController window] display];
    [[briefAlertWindowController window] makeKeyAndOrderFront:nil];
}

and dismissing the mini-alert:

- (void)dismissMiniAlert
{
    NSWindow * theWindow = [briefAlertWindowController window];
    [theWindow orderOut:nil];
}

NOTE that neither NSWindow not NSWindowController have been derived/subclassed for this mini-alert.

  • I'm using the term "mini-alert", because I've noticed people get annoyed about the concept of a "splash screen". While the functionality IS similar -- I'm really just trying to let the user know that an unavoidably long operation is taking place.
SMGreenfield
  • 1,680
  • 19
  • 35

1 Answers1

3

It sounds like a threading problem. The splash window can't draw itself on the main thread because the main thread is busy doing the processor-intensive operation. Properly, your processor-intensive stuff should all be happening on a background thread. If you can't do that, you need at least to get off the main thread long enough to give the runloop a chance to draw your window. Just introduce a delay.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • You're clearly correct, I just need small delay before continuing on. Any suggestion on how best to introduce a delay that won't block the runloop? I tried sleep(n) but that clearly doesn't work. – SMGreenfield Dec 01 '16 at 08:20
  • 1
    The usual way is `dispatch_after`. Or `performSelector:afterDelay:`. – matt Dec 01 '16 at 11:43
  • But please note that what I said about getting the processor-intensive stuff off the main thread still stands. Holding on to the main thread for 10 seconds will spin the pizza of death and the user won't be able to do anything — not even quit. – matt Dec 01 '16 at 21:23
  • this worked spectacularly for the INITIAL display of the mini-alert. For the dismissal, introducing a brief sleep() before displaying an actual NSAlert worked. – SMGreenfield Dec 01 '16 at 21:26
  • Don't get me wrong, I'm glad you're past the initial difficulties. But the fact that there were difficulties at all remains a warning sign. – matt Dec 01 '16 at 21:27
  • for whatever reason, I've never seen the SBBOD during the processor-intensive code. But even if it did (and that's why I want the mini alert already displayed) -- this is a helper app that infrequently deals with registration and activation, so unless the user is presented with UI, then I don't want them to be quitting the app. – SMGreenfield Dec 01 '16 at 21:30