Detecting if a custom file icon was set in Cocoa

2019-07-29 11:10发布

问题:

I wrote an app that sets a custom icon for some files, but as the creation of such an icon is quite expensive I'd like to test if a custom icon was already set before. With custom icon I mean an icon that isn't the default icon set by OS X. In particular, I can have different icons for different files having the same type.

I already tried checking [NSURL resourceValuesForKeys:[NSArray arrayWithObjects:NSURLCustomIconKey,NSURLEffectiveIconKey,nil] error:nil], but the object associated with NSURLEffectiveIconKey is always non-nil and NSURLCustomIconKey seems to be nil even if I call [NSURL setResourceValue:myNonNilImage forKey:NSURLCustomIconKey error:nil].

Calling [[NSWorkspace sharedWorkspace] setIcon:myImage forFile:myFilename options:0] by the way seems the only way to change the icon displayed in the Finder.

回答1:

NSURLCustomIconKey always returns nil because support for this key is not implemented. This essential bit of information is mentioned in the header but not in the NSURL documentation. Until it is supported one way to get this information is through deprecated File Manager methods:

- (BOOL)fileHasCustomIcon:(NSString *)path {
    FSRef ref;
    FSCatalogInfo info;

    if (FSPathMakeRef((const UInt8 *)[path fileSystemRepresentation], &ref, NULL) == noErr) {
        if (FSGetCatalogInfo(&ref, kFSCatInfoFinderInfo, &info, NULL, NULL, NULL) == noErr) {
            FileInfo *fileInfo = (FileInfo *)(&info.finderInfo);
            return (fileInfo->finderFlags & kHasCustomIcon) != 0;
        }
    }

    return NO;
}


回答2:

The documentation for NSWorkspace says that setIcon:forFile:options: returns YES if it was successful.

With that information you can simply switch a NSUserDefault boolean. Here some code I used:

if (![[NSUserDefaults standardUserDefaults] boolForKey:@"iconImageSaved"]) {
    if ([[NSWorkspace sharedWorkspace] setIcon:myImage forFile:myFilename options:0])
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"iconImageSaved"];
}

Hope this helps