I'm adding a feature to a Mac program to delete its preferences .plist file, and then relaunch with what are effectively "factory settings". However, the customer for this is leery of using external frameworks like Sparkle. I've looked online for sample code, but much of it seems over-complicated (e.g. adding a category to NSApplication). Also, some of it simply won't work in Lion or later, when you can't use some APIs to launch a GUI process from a non-GUI process.
So is there a simple way to have a Mac GUI app relaunch itself?
For Mountain Lion at least, a slightly fancy version of fork/exec works fine:
void RelaunchCurrentApp()
{
// Get the path to the current running app executable
NSBundle* mainBundle = [NSBundle mainBundle];
NSString* executablePath = [mainBundle executablePath];
const char* execPtr = [executablePath UTF8String];
#if ATEXIT_HANDLING_NEEDED
// Get the pid of the parent process
pid_t originalParentPid = getpid();
// Fork a child process
pid_t pid = fork();
if (pid != 0) // Parent process - exit so atexit() is called
{
exit(0);
}
// Now in the child process
// Wait for the parent to die. When it does, the parent pid changes.
while (getppid() == originalParentPid)
{
usleep(250 * 1000); // Wait .25 second
}
#endif
// Do the relaunch
execl(execPtr, execPtr, NULL);
}
I ran into one gotcha, which is that the relaunched app can wind up in the background. Doing this early in the execution fixes that problem:
[[NSApplication sharedApplication] activateIgnoringOtherApps : YES];