Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a minimal daemon process in a swift 2 command line tool?

What I am trying to do

I want to run a daemon process that can listen to OSX system events like NSWorkspaceWillLaunchApplicationNotification in an command line tool xcode project? Is that possible? And if not, why not and are there any work arounds or hacks?

Some code samples

The following sample code from a swift 2 cocoa application project sets up a system event listener, which calls WillLaunchApp every time an OSX app gets started. (this works just fine)

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationDidFinishLaunching(aNotification: NSNotification) {
        NSWorkspace.sharedWorkspace()
            .notificationCenter.addObserver(self,
                selector: "WillLaunchApp:",
                name: NSWorkspaceWillLaunchApplicationNotification, object: nil)
    }

    func WillLaunchApp(notification: NSNotification!) {
        print(notification)
    }
}

In contrast this simingly similar swift 2 command line tool project will not call WillLaunchApp.

import Cocoa

class MyObserver: NSObject
{
    override init() {
        super.init()
        NSWorkspace.sharedWorkspace()
            .notificationCenter.addObserver(self,
                selector: "WillLaunchApp:",
                name: NSWorkspaceWillLaunchApplicationNotification, object: nil)
    }

    func WillLaunchApp(notification: NSNotification!) {
        // is never called
        print(notification)
    }
}

let observer = MyObserver()

while true {
    // simply to keep the command line tool alive - as a daemon process
    sleep(1)
}

I am guessing I am missing some cocoa and/or xcode fundamentals here, but I cannot figure out which ones. Maybe it is related to the while-true loop, which might be blocking the events. If so, is there a correct way to run a daemon process?

like image 529
Marco Pashkov Avatar asked Jul 17 '15 06:07

Marco Pashkov


Video Answer


2 Answers

It turns out using while true loop does block the main-thread. Simply replace the while true loop with NSRunLoop.mainRunLoop().run() and you have a daemon process.

I read the sources of swifter (a swift-based server), which is doing the same.

like image 145
Marco Pashkov Avatar answered Sep 18 '22 08:09

Marco Pashkov


In Swift 3 and later, the equivalent code is:

RunLoop.main.run()
like image 25
rsfinn Avatar answered Sep 21 '22 08:09

rsfinn