4

I have an application consisting of the following single .m file:

#import <Cocoa/Cocoa.h>

int main(int argc, char* argv[]) {
  [[[NSThread alloc] initWithBlock: ^{
    sleep(2);
    dispatch_async(dispatch_get_main_queue(), ^{ 
      NSLog(@"Stop");
      [[NSApplication sharedApplication] stop:nil];
    });
  }] start];
  [[NSApplication sharedApplication] run];
  NSLog(@"Run finished");
  return 0;
}

According to the developer documentation, stop should stop the main loop (run), but it doesn't (at least not on OS X 10.12 and 10.13). There's also terminate, but this exits the program too soon. I also tried setting an NSApplicationDelegate that implements applicationShouldTerminate, but this is never called.

How can I make sure the main run loop is (cleanly) exited?

Note: The shared application main loop is necessary because there is UI work being done elsewhere. More concretely, this is giving problems in the Go WDE UI library, which uses Cocoa to provide a window to a Go application.

Remko
  • 823
  • 6
  • 16
  • 1
    There isn't enough context to answer the question. Off the cuff, if you're writing a command line tool, it should be structured as a command line tool and not use NSApplication at all. – bbum Dec 31 '17 at 22:52
  • @bbum I didn't add any context because it didn't seem relevant to the problem, and would only complicate the question. Anyway, added the context of the request. – Remko Jan 02 '18 at 16:03

2 Answers2

4

The documentation for -stop: says:

[C]alling this method from a timer or run-loop observer routine would not stop the run loop because they do not result in the posting of an NSEvent object.

A block dispatched to the main queue is similar in that it doesn't post an event. You can try posting an NSEventTypeApplicationDefined event after calling -stop:.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
2

After investigating this further, it seems that the UI loop stop request is only processed after a UI event (so not just after a main loop event). So, it works in response to a UI event, but not in a thread like I did in my example.

Triggering a UI event after a stop request (e.g. a programmatic resize works for me) causes the loop to end.

Remko
  • 823
  • 6
  • 16