ARC and CFRelease?

12,161

Solution 1

You can't release mimeType because you don't own it. You didn't transfer ownership with the __bridge cast.

You should be releasing uti since you have created it.

You should also release extension since you created it as well, but that will likely cause issues with ext. Instead, transfer ownership to ext.

I'd suggest the following:

+ (NSString *) fileExtensionForMimeType:(NSString *)type {
    CFStringRef mimeType = (__bridge CFStringRef)type;
    CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
    CFStringRef extension = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension);

    NSString *ext = (__bridge_transfer NSString *)extension;

    // CFRelease(mimeType); // not owned
    if (uti) CFRelease(uti);
    // CFRelease(extension); // ownership was transferred

    return ext;
}

Solution 2

Check out WWDC 2012 - Modern Objective-C which outlines new guidelines for Core Foundation objects and ARC. It's about 37:35 into that video. In short, Core Foundation functions with Copy or Create in the name create an object that has transferred ownership to your app, and your app is responsible for releasing it.

Anyway, if ownership has been transferred via a Core Foundation method with Copy or Create in the name, you can either release manually it with CFRelease when you're done with it, or, easier, you can transfer ownership to ARC and let it take care of it. Historically, to transfer ownership to ARC, we used __bridge_transfer, but they now recommend CFBridgingRelease (though the latter is just a macro for the former). And, obviously, if you have some Core Foundation object that you retrieved via some other mechanism other than a function with Copy or Create in the name, you should neither CFRelease it nor transfer ownership to ARC.

By way of illustration, this method accomplishes what you want:

+ (NSString *) fileExtensionForMimeType:(NSString *)type {

    NSString *uti = CFBridgingRelease(UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType,
                                                                            (__bridge CFStringRef)type,
                                                                            NULL));

    return CFBridgingRelease(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)uti,
                                                             kUTTagClassFilenameExtension));
}
Share:
12,161
PaReeOhNos
Author by

PaReeOhNos

Updated on June 07, 2022

Comments

  • PaReeOhNos
    PaReeOhNos almost 2 years

    I'm slightly confused. Everywhere I've read, suggest that when using ARC, you still need to release core foundation objects which makes sense, ARC doesn't manage them. However, I've got a method which uses some CF methods/objects which I used CFRelease on, but that then caused the app to crash. Uncommenting my CFReleases fixes the issue but then I'm assuming I've got a memory leak?

    Could someone please explain which things need releasing and which don't, or anything else that's wrong with this code?

    + (NSString *) fileExtensionForMimeType:(NSString *)type
    {
        CFStringRef mimeType = (__bridge CFStringRef)type;
        CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
        CFStringRef extension = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension);
    
        NSString *ext = (__bridge NSString *)extension;
    
        // CFRelease(mimeType);
        // CFRelease(uti);
        // CFRelease(extension);
    
        return ext;
    }
    

    The three commented out CFRelease calls fix the issue as mentioned, but I know it's wrong. What should I be doing?

  • onevcat
    onevcat over 11 years
    And as @rmaddy said, add a __bridge_transfer on extension to transfer the retain count affair from CF to NSObject.
  • Rob
    Rob over 11 years
    +1 At WWDC 2012, Apple suggested CFBridgingRelease rather than __bridge_transfer. Also, are you entirely sure you need CFRelease(extension) because you've transferred ownership to ARC in the __bridge_transfer to ext.
  • rmaddy
    rmaddy over 11 years
    I thought CFBridgingRelease was the same as __bridge_transfer. The docs don't indicate there is any difference. Regardless, I think you are right about not releasing extension due to the transfer. I'll update my answer. Thanks.
  • Rob
    Rob over 11 years
    Yep, if you look at the definition of CFBridgingRelease, it just does __bridge_transfer, but I assume Apple recommended the new syntax for a reason. I don't know if it's for readability or whether they have some future aspirations for CFBridgingRelease. Either is fine, I'm sure, though.
  • rmaddy
    rmaddy over 11 years
    @Rob Personally I think __bringing_transfer is clearer than CFBridgingRelease. The latter doesn't seem to indicate any transfer of ownership - but that's just my own opinion.
  • Roman B.
    Roman B. over 10 years
    ATTENTION! Should check uti for being NULL before releasing. Just got myself into this crash trap on a big array of files. So, if (uti != NULL) CFRelease(uti);