Search code examples
cocoauser-agentnsapplication

How do I run code when a user agent process terminates?


What I want

I want a helper app user agent (LSUIElement in Info.plist is True) to add itself to the login items on terminate.

The Problem

I can't get any code to run before the helper app process terminates. My "add to login items" code runs fine.

Background

  • I've got a helper app user agent process that runs all the time
  • On first launch, it adds itself to login items
  • If the app was moved, on next login, the helper app process can't be found and so isn't launched

What I've Tried

I wonder if I should subclass NSApplication and override terminate: or stop: and put my code in there, but that seems overkill. Surely there's a better way?

I've tried all these different things in the NSApp delegate:

-(void)applicationWillTerminate:(NSApplication *)sender {
     [self addHelperAppToLoginItems]
}

-(void)applicationDidTerminate:(NSApplication *)sender {
     [self addHelperAppToLoginItems]
}

-(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
     [self addHelperAppToLoginItems]
}

-(void)applicationDidFinishLaunching:(NSNotification *)aNotification {
     [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self 
                                                            selector:@selector(addHelperAppToLoginItems) 
                                                                name:NSWorkspaceDidTerminateApplicationNotification
                                                              object:nil];  

}

-(void)addHelperAppToLoginItems {
      // This code never gets called!
}

Why do the NSApplication delegate methods not work with a user agent process?

And how can I get the process to check the login items on terminate?

I'd be very grateful for any help. Thanks!

UPDATE 1 6/2/11

After some further digging, the problem is more that processes never really get quit, it's more common for them to get killed by the OS.

This means when you choose to "Quit" a process in Activity Monitor or you shut down the computer, the terminate delegate methods don't get called.

When the following Applescript is run, the delegate methods do get called:

tell application "System Events"
    tell application "LapsusHelperApp"
         quit
    end tell
end tell

Solution

  • After some further digging, the problem is more that processes never really get quit, it's more common for them to get killed by the OS.

    This is because you have sudden termination enabled for your application. It's opt-in, so simply remove that key-value pair from your Info.plist and you will then start getting applicationWillTerminate: messages.

    Also, the Terminate button in Xcode (at least in 3.x) always works the same way sudden termination does, so you will never get a applicationWillTerminate: message when terminating your app from Xcode.

    By the way:

    • applicationWillTerminate: is a notification message, so its argument is an NSNotification object, not an NSApplication object.
    • There is no applicationDidTerminate:. A moment's reflection will reveal why. ☺