Last Updated: February 25, 2016
·
765
· chrisjdavis

Don't let phantom applications crash your Mac app.

Your lovely mac doesn't cleanup after itself well when you install and then delete a browser. Consider the following code:

- (void)setUpExternalBrowsers {
    browsers = CFBridgingRelease(LSCopyAllHandlersForURLScheme(CFSTR("https")));

    for (int i = 0; i < [browsers count]; i++ ) {
        NSDictionary *row = [browsers objectAtIndex:i];

        NSString *path = [[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:[NSString stringWithFormat:@"%@", row]];

        NSString *appName = [[path componentsSeparatedByString:@"/"] lastObject];
        NSString *name = [appName stringByReplacingOccurrencesOfString:@".app" withString:@""];
         [otherBrowsers addItemWithTitle:name];
    }
}

Looks good right? Grab a list of installed applications that respond to https and then add them to our MutableArray. The problem is the user who has installed your application installed and then deleted Mike's Great WebBrowser, but Mac OS X left some cruft behind that makes it look like Mike's app is still installed.

When this method is run you will trigger an Uncaught exception and your app will take a one way trip to crashville.

To help Mac OS X do the right thing, simply instantiate the filemanager and use it to check if an executable actually lives where MacOS X thinks it does.

- (void)setUpExternalBrowsers {
    browsers = CFBridgingRelease(LSCopyAllHandlersForURLScheme(CFSTR("https")));
    NSFileManager *fileManager  = [NSFileManager defaultManager];

    for (int i = 0; i < [browsers count]; i++ ) {
        NSDictionary *row = [browsers objectAtIndex:i];

        NSString *path = [[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:[NSString stringWithFormat:@"%@", row]];

        if ([fileManager fileExistsAtPath:path]) {
            NSString *appName = [[path componentsSeparatedByString:@"/"] lastObject];
            NSString *name = [appName stringByReplacingOccurrencesOfString:@".app" withString:@""];
            [otherBrowsers addItemWithTitle:name];
        }
    }
}

Easy Peasy.