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;
}