Swift: Manual retain/release
Old school
While creating ThreadLocalSlot<T>, I needed to call the posix posix_getspecific
and posix_setspecific
methods. Not only that, I needed to store an Objective-C object in a plain old void*
. How can we accomplish that in Swift?
The key is Unmanaged
. It contains magic sauce to let us turn an AnyObject
into a COpaquePointer
, which is implicitly convertible to most of the other C-pointer types in Swift. It also lets us apply retain
or release
to an object arbitrarily. Granted, you can certainly shoot yourself in the foot, but we all lived dangerously before ARC.
let unmanaged = Unmanaged.passRetained(value)
let ptr = unmanaged.toOpaque()
Here you can see that we are telling Unmanaged
that we are going to pass value
to a method somewhere that expects a +1 retain count. This will cause Unmanaged
to retain
the object for us. passRetained()/passUnretained()
are how we get an object into the Unmanaged
world.
Next we grab the raw pointer value and voila! we have escaped the safety of Swift and ARC, free to leak memory, crash, or otherwise get up to no good.
let unmanaged:Unmanaged<T> = Unmanaged.fromOpaque(ptr)
Here we take a raw pointer and convert it back to Unmanaged
. In this case, T
will be whatever type lives at the pointer's address because Swift can't figure that out on its own. Get that wrong and you're in for a real fun crash somewhere down the line; or possibly just random corruption. Technically the compiler is free to reformat your disk and print the first five lines of Hamlet repeatedly to the console, but that's the nature of Undefined behavior.
Anyway, once we are back in Unmanaged
land, we can release the object with unmanaged.release()
, or unmanaged.autorelease()
, or we can convert it back to a type Swift knows about and bring it back under ARC's control:
let obj = unmanaged.takeUnretainedValue()
In this case, we tell Unmanaged
not to change the retain count. The corresponding takeRetainedValue()
is also available. This is how we take an object back out of Unmanaged
.
Next time: Let's sling some C-style arrays
This blog represents my own personal opinion and is not endorsed by my employer.