Search code examples
objective-cxcodemultithreadingdaemonnsnotifications

Developing a non-GUI user agent in Objective-C using NSDistributedNotificationCenter


I would like to create a user agent in Objective-C that listens for notifications from the default NSDistributedNotificationCenter. The agent will not have a GUI. When I create a Cocoa application (I will also be using Distributed Objects, which I think is only in Cocoa) in Xcode, however, Xcode sets the project as a GUI application.

In the main function, I remove the NSApplicationMain(...) function call to remove the GUI elements from the application. However, now I can't get the thread to wait (listen for) notifications coming in from the NSDistributedNotificationCenter. The app just starts and quits immediately.

I looked into using the NSRunLoop from the current NSThread, however, it seems that NSRunLoops only wait on NSPorts. There's no mention of waiting on NSNotifications.


Solution

  • NSDistributedNotificationCenter is Foundation, so you don't need to create a GUI app. You can create a command line template, for example, and run it from terminal. As a very simple example, you could create an example that just prints out every distributed notification it receives below.

    To build, copy into an Xcode template for a Foundation command line app, or simply copy into a text file named something like test_note.m and build according to the comments. In this example, the application will never end (CFRunLoopRun() never returns) and you will have to kill it by hitting CTRL+C from the terminal or killing it with something like kill or the activity monitor.

    // test_build.m
    // to build: clang -o test_build test_build.m -framework foundation
    
    #import <Foundation/Foundation.h>
    
    @interface Observer : NSObject
    
    - (void)observeNotification:(NSNotification*)note;
    
    @end
    
    @implementation Observer
    
    - (void)observeNotification:(NSNotification*)note
    {
      NSLog(@"Got Notification: %@", note);
    }
    
    @end
    
    int main (int argc, char const *argv[])
    {
      @autoreleasepool {
        Observer* myObserver = [[Observer alloc] init];
        [[NSDistributedNotificationCenter defaultCenter] addObserver:myObserver selector:@selector(observeNotification:) name:nil object:nil];
        CFRunLoopRun();
      }
      return 0;
    }