Reputation: 9527
I have several UIView
or UITableViewCell
. Inside I have C callback, for example:
CCallback(bridge(self),
{(observer, data) -> Void in
let mySelf = Unmanaged<DetailedView>.fromOpaque(observer!).takeRetainedValue()
mySelf.fillLoadedData(data: data)
});
Somewhere else
func bridge<T : AnyObject>(_ obj : T) -> UnsafeMutableRawPointer {
return UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque())
}
In C:
void CCalback(void * classPtr, void(*callback)(void *, MyData)){
//fill data
callback(classPtr, data)
}
Should I use takeUnretainedValue
or takeRetainedValue
in closure? As far as I understand this, retained will increase objects reference count, so it wont be auto-destructed? Otherwise, if I use takeUnretainedValue
, if self is auto-released, this will crash, so using takeRetainedValue
will prevent it. Am I correct?
Upvotes: 3
Views: 877
Reputation: 539815
An object pointer can be converted to a Unsafe(Mutable)RawPointer
(the Swift
equivalent of the C void *
) with or without retaining the object:
let ptr = UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque())
// Does not retain `obj`
let ptr = UnsafeMutableRawPointer(Unmanaged.passRetained(obj).toOpaque())
// Retains `obj`
The conversion back to an object pointer (often done in a callback function called from C) can be with or without consuming a retain:
let obj = Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
// Does not consume a retain
let obj = Unmanaged<T>.fromOpaque(ptr).takeRetainedValue()
// Consumes a retain
If the lifetime of obj
is guaranteed while the callback is active
then the easiest way is to use the "unretained" conversions in both directions. You are responsible for retaining obj
while the
callback is active, e.g. by unregistering the callback before obj
is deinitialized.
The alternative is to use passRetained()
to convert obj
to
a pointer. This retains the object and therefore keeps it "alive".
The callback can still use the "unretained" conversion to convert
the pointer to an object pointer, without decreasing the retain count.
But there must be exactly one takeRetainedValue()
call to consume the
retain. After that, the object can be destroyed if there are no
other references to it.
More generally, each call to passRetained(obj)
increases the retain
count and each call to takeRetainedValue()
decreases it, so they must be properly balanced.
Upvotes: 4