I have a myCGEventCallback function for CGEventTap that takes parameter "refcon:UnsafeMutableRawPointer?".
I pass my main ViewController as a pointer to the callback using
let pointer = UnsafeMutableRawPointer(Unmanaged.passRetained(self).toOpaque())
Then inside the callback, I access the ViewController using
let sender:ViewController = Unmanaged<T>.fromOpaque(refcon!).takeRetainedValue()
When the event occurs, the callback works fine. However, it only works 4 times. When the same event occurs for the fifth time, my app crashes, and the debug console just says "LLDB".
It looks like it crashes when I try to access the sender. "sender.someFunction()". It crashes before the function gets to run, so I assume it has a problem accessing the sender.
Is this because of poor memory management? Maybe I need to deallocate the pointer? If so, how and where would I do that?
Thanks!
passRetained(self)
increases the retain count for self
(which is your
view controller instance) by one. Each call to takeRetainedValue()
decreases
the retain count by one. Those calls must be properly balanced, otherwise
the object might be destroyed too early.
In your case, where the pointer is created once, but used several times in a callback function, you should use the “unretained” conversion in the callback:
let sender = Unmanaged<ViewController>.fromOpaque(refcon!).takeUnretainedValue()
so that no ownership is transferred.
There are two patterns how to create the pointer:
If the callback is guaranteed to be active only during the lifetime of the view controller then you can create the pointer without retaining the instance:
let pointer = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
Otherwise, if the view controller instance should be kept alive while the callback is active, retain it while creating the pointer
let pointer = UnsafeMutableRawPointer(Unmanaged.passRetained(self).toOpaque())
and release it eventually, when the callback is no longer active:
Unmanaged<ViewController>.fromOpaque(pointer).release()