Reputation: 4760
I am working on a Swift project that uses a C library wrapped In a C++.
The library offers you the possibility to get/set variables synchronously and asynchronously.
The Library as callback methods that notifies when and even has happened.
I have this function in swift:
/*** Convert const void* To Any T ***/
func bridgeToTypeRetained<T : AnyObject>(ptr : UnsafeMutableRawPointer) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeRetainedValue()
}
func bridgeToTypeUnretained<T : AnyObject>(ptr : UnsafeRawPointer) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
}
and
/*** Convert const void* To Any T ***/
func bridgeToPointerRetained<T : AnyObject>(obj : T) -> UnsafeMutableRawPointer {
return UnsafeMutableRawPointer(Unmanaged.passRetained(obj).toOpaque())
}
func bridgeToPointerUnretained<T : AnyObject>(obj : T) -> UnsafeMutableRawPointer {
return UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque())
}
For Implementing Callbacks from the Library, In the Library I have the following definitions:
DllExport void STDCALL CpProxyAvOpenhomeOrgInfo1SetPropertyTrackCountChanged(THandle aHandle, OhNetCallback aCallback, void* aPtr);
typedef void (STDCALL *OhNetCallback)(void* aPtr);
Then in swift I use the following Code:
CpProxyAvOpenhomeOrgInfo1SetPropertyTrackCountChanged(myHandle, { (pointer) in
if pointer != nil{
let myClass:MyClass = bridgeToTypeRetained(ptr: pointer!)
myClass.aValu = 0 //CRASH BAD ACCESS
let myClass:MyClass = bridgeToTypeUnretained(ptr: pointer!)
myClass.aValu = 0 //NO CRASH
}
}, bridgeToPointerRetained(obj: self))
And for implementing an asynchronously action, In the Library I have they following definitions:
DllExport void STDCALL CpProxyAvOpenhomeOrgInfo1BeginCounters(THandle aHandle, OhNetCallbackAsync aCallback, void* aPtr);
typedef void (STDCALL *OhNetCallbackAsync)(void* aPtr, OhNetHandleAsync aAsync);
Then swift I use the following code
let classCallback = ClassCallback()
classCallback.classObject = self
CpProxyAvOpenhomeOrgInfo1BeginCounters(prxHandleId, { (pointer, ohNetAsync) in
if pointer != nil && ohNetAsync != nil{
let classCallback : ClassCallback = bridgeToTypeRetained(ptr: pointer!)
classCallback.classObject.aValue = 1 //NO CRASH
}
}, bridgeToPointerRetained(obj: classCallback))
So My questions would be:
Thank you.
Upvotes: 0
Views: 742
Reputation: 2014
You need to pass in a retained value if you want your ClassCallback
to exist even if all your Swift references to it go away, this creates a memory leak without proper cleanup logic also being added in. If you pass an unretained value then if all of your swift references have gone away when you try to get back your ClassCallback
you will crash.
In your callback, you can take an unretained reference to get the object assuming you want it to continue to exist with its current reference count at the end of scope. If you take a retained reference the reference count will decrement and destroy the object if that was the last reference.
What I generally do is pass in a retained reference and take an unretained reference until I am ready to dispose of the callback object. When that happens I take the retained value of the context pointer (aPtr
in your case) to balance the retained pass and replace it with a new appropriate value.
Upvotes: 3