What is Unmanaged, and what do takeRetainedValue and takeUnretainedValue mean?
Predict first
What does this print?
final class A { deinit { print("deinit") } }
let u = Unmanaged.passRetained(A())
print("created")
u.release()
print("released")
- created, released, deinit
- created, deinit, released
- deinit, created, released
Predict first
What does this print?
final class A { deinit { print("deinit") } }
var a: A? = A()
let u = Unmanaged.passUnretained(a!)
a = nil
print("cleared")
_ = u
- cleared, deinit
- deinit, cleared
Mental model. Unmanaged is taking the sign-out sheet away from the clerk. You can now lend the book out with no record, and you are responsible for getting it back.
Unmanaged<T> wraps a class reference and opts out of ARC: you hold a plain pointer and manage the count yourself. passRetained(obj) gives you an unmanaged reference and adds one to the count (you must later release() it), while passUnretained(obj) adds nothing and does not keep the object alive. Coming back, takeRetainedValue() converts a +1 reference into a normal managed one and consumes that count, while takeUnretainedValue() hands you a managed reference without changing the count.
You need it at the edge of C. A C callback that takes a void * context uses Unmanaged.passRetained(self).toOpaque() to hand the object through, and fromOpaque(_:) to get it back, with a release when the callback is finished. For Core Foundation, the Create and Copy rule means a function with those names returns an owned object (takeRetainedValue()), while a Get function returns a borrowed one (takeUnretainedValue()). Most modern CF APIs are annotated so Swift handles it for you.
passRetained holds the object alive with an extra count. Nothing else owns it, so release() is the moment it dies.
passUnretained adds no count, so clearing the only strong reference frees the object immediately. u now dangles.
Common traps
- Using
takeRetainedValue()on a borrowed reference. It releases a count you never owned, and the object is freed early. - Using
passUnretainedand forgetting the object can die. The unmanaged reference dangles if no other strong reference exists.
They might follow up with
- How do you recognise an owned CF return? The function name contains
CreateorCopy. - What is
toOpaque()for? It gives the raw pointer you pass as C user data.
Related questions
- 3.1.4 What did manual reference counting look like, and which rules did ARC automate?
- 3.2.4 What is unowned(unsafe), and when would you ever use it?
- 3.6.4 What hidden retains and autoreleases does calling Objective-C add?
← What do guaranteed and owned parameters mean, and what do borrowing… What hidden retains and autoreleases does calling Objective-C add? →