Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stopping the NSApplication main event loop

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.

like image 418
Remko Avatar asked Sep 06 '25 03:09

Remko


2 Answers

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:.

like image 92
Ken Thomases Avatar answered Sep 07 '25 19:09

Ken Thomases


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.

like image 36
Remko Avatar answered Sep 07 '25 19:09

Remko