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.