Vincent Gable’s Blog

October 5, 2008

Restarting Your Mac OS X Cocoa Application

Filed under: Bug Bite,Cocoa,MacOSX,Objective-C,Programming,UNIX | , ,
― Vincent Gable on October 5, 2008

Restarting your own application is a tricky thing to do, because you can’t tell yourself to start up when you aren’t running. Here is one solution, use NSTask to run a very short script that you can embed right in your Objective-C code:
kill -9 YourPID
open PathToYourApp

Something to be aware of, kill -9 will immediately terminate your application, without going through the usual applicationWillTerminate: business that happens when an application quits more gracefully.

- (void) restartOurselves
{
   //$N = argv[N]
   NSString *killArg1AndOpenArg2Script = @"kill -9 $1 \n open \"$2\"";
   
   //NSTask needs its arguments to be strings
   NSString *ourPID = [NSString stringWithFormat:@"%d",
                  [[NSProcessInfo processInfo] processIdentifier]];
   
   //this will be the path to the .app bundle,
   //not the executable inside it; exactly what `open` wants
   NSString * pathToUs = [[NSBundle mainBundle] bundlePath];
   
   NSArray *shArgs = [NSArray arrayWithObjects:@"-c", // -c tells sh to execute the next argument, passing it the remaining arguments.
                killArg1AndOpenArg2Script,
                @"", //$0 path to script (ignored)
                ourPID, //$1 in restartScript
                pathToUs, //$2 in the restartScript
                nil];
   NSTask *restartTask = [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:shArgs];
   [restartTask waitUntilExit]; //wait for killArg1AndOpenArg2Script to finish
   NSLog(@"*** ERROR: %@ should have been terminated, but we are still running", pathToUs);
   assert(!"We should not be running!");
}

WARNING: don’t make the same mistake that I did and test restartOurselves without some kind of guard to keep your application from restarting forever. It is very difficult to kill such a beast, because whenever it starts up it takes keyboard focus away from what you are doing…. well I’m sure you get the idea.

- (BOOL) weHaveRunBefore {
   NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
   BOOL weHaveRunBefore = [prefs boolForKey:@"weHaveRunBefore"];
   [prefs setBool:YESs forKey:@"weHaveRunBefore"];
   [prefs synchronize];
   return weHaveRunBefore;
}

1 Comment »

  1. Awesome, thank you for posting this!!

    Comment by Alex — February 14, 2009 @ 10:58 pm

RSS feed for comments on this post.

Leave a comment

Powered by WordPress