ARC和CFRelease?

时间:2012-12-28 03:49:25

标签: objective-c ios cocoa-touch automatic-ref-counting

我有点困惑。我读过的每个地方都建议,在使用ARC时,你仍然需要释放有意义的核心基础对象,ARC不管理它们。但是,我有一个方法,它使用了一些我使用CFRelease的CF方法/​​对象,但这导致应用程序崩溃。取消注释我的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;
}

三个注释掉的CFRelease来电解决了上述问题,但我知道这是错误的。我该怎么办?

3 个答案:

答案 0 :(得分:36)

您无法释放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; }

我建议如下:

{{1}}

答案 1 :(得分:15)

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

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

通过举例说明,此方法可以实现您的目的:

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

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

    return CFBridgingRelease(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)uti,
                                                             kUTTagClassFilenameExtension));
}

答案 2 :(得分:0)

一般来说,我认为您应该尝试评论第一个CFRelease(mimeType)行,并取消注释后面两行:CFRelease(uti)和CFRelease(扩展名)。你建立一个免费的桥接器来输入NSString,ARC将处理这个版本。但是uti和扩展名是作为CFString创建/复制的。 ARC不知道如何处理它们(记住ARC是NSObject的编译器功能),所以你需要CF发布它们。