【问题标题】:When to use takeUnretainedValue() or takeRetainedValue() to retrieve Unmanaged Objects in Swift?何时使用 takeUnretainedValue() 或 takeRetainedValue() 在 Swift 中检索非托管对象?
【发布时间】:2015-05-16 21:57:00
【问题描述】:

根据Using Swift with Cocoa and Objective-C,您可以使用takeUnretainedValue()takeRetainedValue() 来告诉Swift 如何为这样的函数管理对象的内存:

func StringByAddingTwoStrings(CFString!, CFString!) -> Unmanaged<CFString>!

什么时候必须使用takeUnretainedValue()takeRetainedValue()

当我使用 ARC 时,是否总是takeUnretainedValue()

【问题讨论】:

    标签: ios objective-c iphone swift


    【解决方案1】:

    当非托管对象的保留计数为 +1 并且您希望 ARC 负责在您完成后释放该对象时,您可以使用 takeRetainedValue。例如,如果您调用名称中带有CreateCopy 的Core Foundation 函数(请参阅Core Foundation 的内存管理编程指南中的Create Rule),它会返回一个非托管对象你负责发布,你一般使用takeRetainedValue,这样就为你发布了(或者,如果你不这样做,你必须自己手动使用CFRelease或者类似的功能发布)。当对象的所有权尚未转移给您时,您使用takeUnretainedValue,因此您不希望 ARC 在对象超出范围时为您释放对象。

    所以,当你调用takeUnretainedValuetakeRetainedValue 时,它只取决于被调用函数返回的对象类型。作为一般经验法则,如果对象是从名称中带有CreateCopy 的Core Foundation 函数返回的,请使用takeRetainedValue。否则使用takeUnretainedValue


    如果你调用错误的方法会发生什么,如果你在传递一个 +1 对象时调用 takeUnretainedValue(例如,从 Core Foundation 函数返回的对象,名称中带有 CreateCopy ),除非您明确地 CFRelease 它,否则您的应用程序将会泄漏。运行应用程序时您可能不会立即注意到偶尔的泄漏,但可以通过观察应用程序的内存使用情况来观察(例如,如果您使用 Instruments 分析您的应用程序)。但是,如果您不解决这些泄漏,您的应用程序最终可能会收到内存警告。

    另一方面,如果您在尚未为您保留的对象上调用 takeRetainedValue(由名称中没有 CreateCopy 的函数返回),则应用程序可能会崩溃当物体被释放时。有时这不会立即表现出来(直到最后一个强引用被解决),但它通常会导致应用程序的灾难性故障。

    因此,明智地选择takeUnretainedValuetakeRetainedValue 非常重要。

    【讨论】:

    • 我如何通过 API 知道所有权是否转移给我?
    • 为了补充 Rob 的答案,链接到的文档强调了这一点:“您可以根据您调用的 API 返回未保留对象还是保留对象来选择要使用的方法。”
    • @confile 该方法的目的可能很明显 - 如果它返回一个 新对象,您必须保留它,否则它将消失。如果它返回一个保留的对象(比如集合中的一个项目),那么你不拥有它,所以你不保留它。该方法的文档可能会澄清。
    • @confile 如果您在传递保留对象时调用takeUnretainedValue,您的应用程序将泄漏。您可能不会注意到除了您的应用程序会泄漏(如果您使用 Instruments 可以看到)并且您最终可能会收到内存警告。如果您在应该调用未保留版本时调用 takeRetainedValue,则应用程序可能会崩溃(尽管不一定立即)。
    • @confile "我如何通过 API 知道所有权是否已转移?"约定是,如果函数名称中包含CreateCopy,则所有权已转移。如果不是,则所有权尚未转移。
    【解决方案2】:

    引自 NSHipster:

    https://nshipster.com/unmanaged/

    一个非托管实例包装一个 CoreFoundation 类型 T,只要非托管实例本身在范围内,它就会保留对基础对象的引用。有两种方法可以从非托管实例中获取 Swift 托管的值:

    • takeRetainedValue() 返回一个 Swift 管理的对包装实例的引用,同时减少引用计数 - 与创建规则函数的返回值一起使用。

    • takeUnretainedValue() 返回一个由 Swift 管理的对包装实例的引用,而不减少引用计数——与 Get Rule 函数的返回值一起使用。

    【讨论】:

      猜你喜欢
      • 2022-09-23
      • 2017-11-26
      • 2016-10-28
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 2012-09-23
      • 2016-02-21
      • 1970-01-01
      相关资源
      最近更新 更多