While creating ThreadLocalSlot<T>, I needed to call the posix
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
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
retain the object for us.
passRetained()/passUnretained() are how we get an object into the
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.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
Next time: Let's sling some C-style arrays
This blog represents my own personal opinion and is not endorsed by my employer.