释放Core Foundation对象引用

20

我需要释放Core Foundation对象来清理内存吗?如果是这样的话,应该如何释放?

比如在下面的代码中:

ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef peopleArray = ABAddressBookCopyArrayOfAllPeople(addressBook);

我需要释放peopleArray吗?addressBook呢?

5个回答

26

Core Foundation内存管理的规则与Cocoa中的类似:如果返回引用的方法包含“create”或“copy”一词,则您拥有该引用并必须调用CFRelease()来放弃所有权。否则,您不拥有该引用,并且必须调用CFRetain来获取所有权(必然需要随后的CFRelease来放弃该新所有权)。这些规则来源于Core Foundation内存管理编程指南:

  • 如果您创建一个对象(直接或通过复制另一个对象-请参见“创建规则”),则拥有它。
  • 如果您从其他地方获取对象,则不拥有它。如果要防止其被处理,必须将自己添加为所有者(使用CFRetain)。
  • 如果您是对象的所有者,则在完成使用后必须放弃所有权(使用CFRelease)。
在你的示例中,必须释放addressBookpeopleArray。由于Core Foundation中没有autorelease的等效方法,如果您从方法返回引用,则应该不释放数组并返回它。除非你是故意这样做,否则你应该在方法名中包含"create"以指示调用者现在拥有返回对象的引用。在这种情况下,CFArray可以桥接到NSCFArray,这是一个继承自NSObject的Objective-C对象。因此,如果需要从函数/方法返回它,您可以将peopleArray转换为NSArray*并进行autorelease操作。
return [(NSArray*)peopleArray autorelease];

请注意,这仅适用于免费通行的桥接类。我的理解是,制作自己的免费通行的桥接类相当困难,只有原始(字符串、数组等)CF类是免费通行的桥接,因此这种方法并不总是有效。最后,如果您可以避免使用autorelease(即使您可以使内存管理更加明确),那可能总是一件好事。

谢谢Barry - 我对Cocoa的内存规则非常熟悉 - 只是不确定CF的规则是否相同。很高兴知道它们是一样的。 - rein
一样的,除了缺少自动释放池... 如果你熟悉Cocoa规则并尽可能避免使用自动释放池,那么你完全可以得心应手。 - Barry Wark
1
通过将对象转换为id类型并调用autorelease方法,可以自动释放使用toll-free bridged的对象:[(id)cfObject autorelease]; - rpetrich
1
好的,在这种情况下,CFArrayRef可以转换为NSArray并自动释放,如[(NSArray)peopleArray autorelease]。我会将其添加到答案文本中。 - Barry Wark
那么如何返回一个非toll-free bridged对象呢? - Conor

26

是的,在CoreFoundation中,对于任何名称中带有Create或Copy的东西,您都需要进行释放。您可以使用CFRelease()来完成此操作。在您的情况下,您应该释放数组和通讯录引用。


谢谢。我在Google上苦苦寻找答案,但却没找到。可能是因为我输入的是“Core Framework”,而不是“Core Foundation”。唉!:) - rein

4

还有一个小细节,目前还没有人提到过,一些CF类与它们的NS对应类有“toll-free bridge”的功能。例如CFStringNSStringCFArrayNSArray。这是相关的,因为您可以直接使用release来释放这些类。

有关更多信息,请参见此StackOverflow问题


3
对于ARC,您可以使用以下方法。
return (__bridge_transfer NSArray*)peopleArray;

"__bridge_transfer"将所有权转移给ARC,因此您无需进行任何其他释放调用。

3
我建议阅读苹果公司有关Core Foundation内存管理的指南,以深入探讨此问题。他们还有一份类似的Cocoa内存管理指南。
要释放CF对象,您需要调用CFRelease函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接