When to use takeUnretainedValue() or takeRetainedValue() to retrieve Unmanaged Objects in Swift?

You use takeRetainedValue when the unmanaged object has a +1 retain count and you want ARC to take care of releasing the object when you're done. For example, if you call a Core Foundation function with Create or Copy in the name (see Create Rule in the Memory Management Programming Guide for Core Foundation) which returns an unmanaged object for which you are responsible for releasing, you generally use takeRetainedValue so that it is released for you (or, if you don't do this, you have to manually release it yourself with CFRelease or similar function). You use takeUnretainedValue when ownership of the object has not been transferred to you and you therefore do not want ARC releasing the object for you when it falls out of scope.

So, as to when you call takeUnretainedValue vs takeRetainedValue, it simply depends upon what sort of object the called function returns. As a general rule of thumb, if the object was returned from a Core Foundation function with Create or Copy in the name, use takeRetainedValue. Otherwise use takeUnretainedValue.


In terms of what happens if you call the wrong method, if you call takeUnretainedValue when you're passed a +1 object (e.g. an object returned from Core Foundation function with Create or Copy in the name), your app will leak unless you explicitly CFRelease it. You may not immediately notice the occasional leak when running the app, but it can be observed by watching your app's memory usage (e.g. if you profile your app with Instruments). But if you leave these leaks unresolved, your app may eventually receive memory warnings.

On the other hand, if you call takeRetainedValue on an object which has not been retained for you (returned by a function that did not have Create or Copy in its name), the app will likely crash when the object is released. Sometimes this won't manifest itself immediately (not until the last strong reference is resolved), but it will generally result in a catastrophic failure of the app.

So judicious selection of takeUnretainedValue vs takeRetainedValue is very important.


Quoting from NSHipster:

https://nshipster.com/unmanaged/

An Unmanaged instance wraps a CoreFoundation type T, preserving a reference to the underlying object as long as the Unmanaged instance itself is in scope. There are two ways to get a Swift-managed value out of an Unmanaged instance:

  • takeRetainedValue() returns a Swift-managed reference to the wrapped instance, decrementing the reference count while doing so—use with the return value of a Create Rule function.

  • takeUnretainedValue() returns a Swift-managed reference to the wrapped instance without decrementing the reference count—use with the return value of a Get Rule function.