ARC和CFRelease?

PaR*_*Nos 33 cocoa-touch objective-c ios automatic-ref-counting

我有点困惑.我读过的每个地方都建议,在使用ARC时,你仍然需要释放有意义的核心基础对象,ARC不管理它们.但是,我有一个方法,它使用我使用的一些CF方法/​​对象CFRelease,但然后导致应用程序崩溃.取消注释我CFRelease的问题解决了这个问题,但后来我假设我有内存泄漏?

有人可以解释哪些东西需要发布,哪些不需要,或者其他任何错误的代码?

+ (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;
}
Run Code Online (Sandbox Code Playgroud)

三个注释掉的CFRelease电话修复了上述问题,但我知道这是错误的.我该怎么办?

rma*_*ddy 38

您无法发布,mimeType因为您不拥有它.您没有使用__bridge演员转让所有权.

你应该发布,uti因为你已经创建它.

您也应该extension在创建它之后发布,但这可能会导致问题ext.相反,将所有权转移到ext.

我建议如下:

+ (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;
}
Run Code Online (Sandbox Code Playgroud)

  • +1在WWDC 2012上,Apple建议使用`CFBridgingRelease`而不是`__bridge_transfer`.另外,你是否完全确定你需要`CFRelease(extension)`因为你已经将`__bridge_transfer`中的所有权转移到`ext`. (5认同)
  • @Rob我个人认为__bringing_transfer比CFBridgingRelease更清晰.后者似乎并没有表明任何所有权的转移 - 但这只是我自己的意见. (3认同)

Rob*_*Rob 15

查看WWDC 2012 - 现代Objective-C,其中概述了Core Foundation对象和ARC的新指南.该视频大概是37:35.简而言之,Core Foundation 在名称CopyCreate名称中的功能创建了一个将所有权转移到您的应用程序的对象,您的应用程序负责释放它.

无论如何,如果所有权已通过Core Foundation方法使用CopyCreate以名称传输,您可以在完成后手动释放CFRelease它,或者更容易,您可以将所有权转移到ARC并让它来处理它.从历史上看,为了将所有权转让给ARC,我们使用了__bridge_transfer,但他们现在推荐CFBridgingRelease(尽管后者只是前者的宏).而且,显然,如果您有一些Core Foundation对象,您通过其他机制检索除了名称Copy或函数之外的其他机制Create,您既不CFRelease应该也不应该将所有权转移给ARC.

举例来说,这种方法可以实现你想要的:

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

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

    return CFBridgingRelease(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)uti,
                                                             kUTTagClassFilenameExtension));
}
Run Code Online (Sandbox Code Playgroud)