How to Use Instance Method as Callback For Function Which Takes Only Func or Literal Closure

how to call a function that takes a function pointer argument in Swift?

customCopyDescription needs to be a free function, not a method. When I copied your code into Xcode I got the error message only when customCopyDescription was inside a class, not otherwise.

Once placeholder return values are added and customCopyDescription is placed at file scope, the code compiles without a problem

Pass an UnsafeMutableRawPointer as a function parameter

SQLite is a pure C library, and SQLite3.sqlite3_bind_text() takes a pointer to a C function as the fifth parameter. Such a parameter is marked with @convention(c) and that must be replicated in your wrapper function:

public func sqlite3_bind_text(_ oP: OpaquePointer!, _ first: Int32,
_ second: UnsafePointer<Int8>!,
_ third: Int32,
_ ptrs: (@convention(c) (UnsafeMutableRawPointer?) -> Void)!) -> Int32 {
SQLite3.sqlite3_bind_text(oP, first, second, third, ptrs)
}

Wrapping C callbacks (without context) into Swift Closures

Solved by using a global variable

public struct glfw {
static func setErrorCallback(cbFun: @escaping ErrorFun) {
_g.errorCB = cbFun
glfwSetErrorCallback { err, desc in
_g.errorCB!(Error(rawValue: err)!, String(utf8String: desc!)!)
}
}
var errorCB: ErrorFun?
}
var _g = glfw()

How can I pass an anonymous method into a closure that captures context in Swift?

I am trying to pass an anonymous function into a method that uses a closure.

This is not precisely the case. CGEvent.tapCreate is a wrapper for the C function CGEventTapCreate, which takes a callback that is a C function. A C function is not a closure. A closure contains both code to execute and any values that it references. It is said to “close over” those values. A C function can't close over any values; it only has access to the arguments passed to it and to global variables.

To work around this behavior, a C API that takes a callback function usually also takes an opaque pointer (void * in C parlance) which you can use to pass in whatever extra state you want. In the case of CGEvent.tapCreate, that is the userInfo or refcon argument (the documentation refers to it by both names). You're passing self as that argument, but you actually want to pass in two values: self and onNameReceived.

One way to solve this is by adding a new instance property to hold onNameReceived for use by the callback, since you can access the instance property through the self reference you recover from refcon.

My preferred solution is to wrap the event tap in a class that lets you use a Swift closure as the handler.

class EventTapWrapper {
typealias Handler = (CGEventTapProxy, CGEventType, CGEvent) -> ()

init?(
location: CGEventTapLocation, placement: CGEventTapPlacement,
events: [CGEventType], handler: @escaping Handler)
{
self.handler = handler

let mask = events.reduce(CGEventMask(0), { $0 | (1 << $1.rawValue) })

let callback: CGEventTapCallBack = { (proxy, type, event, me) in
let wrapper = Unmanaged<EventTapWrapper>.fromOpaque(me!).takeUnretainedValue()
wrapper.handler(proxy, type, event)
return nil
}

// I can't create the tap until self is fully initialized,
// since I need to pass self to tapCreate.
self.tap = nil

guard let tap = CGEvent.tapCreate(
tap: location, place: placement,
options: .listenOnly, eventsOfInterest: mask,
callback: callback,
userInfo: Unmanaged.passUnretained(self).toOpaque())
else { return nil }
self.tap = tap
}

private let handler: Handler
private var tap: CFMachPort?
}

With this wrapper, we can just use a regular Swift closure as the tap handler:

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func startListeningForEvents(onNameReceived: @escaping (String) -> Void) {
self.tap = EventTapWrapper(
location: .cghidEventTap, placement: .tailAppendEventTap,
events: [.leftMouseUp],
handler: { [weak self] (proxy, type, event) in
guard let self = self else { return }
onNameReceived(self.onEventTap(proxy: proxy, type: type, event: event))
})
}

func onEventTap(proxy: CGEventTapProxy, type: CGEventType, event: CGEvent) -> String {
return "hello"
}

private var tap: EventTapWrapper?
}

Please note that this is not a complete example (although it compiles). You also have to enable the tap (with CGEvent.tapEnable) and add it to a run loop (using CFMachPortCreateRunLoopSource and then CFRunLoopAddSource). You also need to remove the source from the run loop in the wrapper's deinit, lest it try to use the wrapper after the wrapper has been destroyed.

Referencing `self` from within a VTCompressionOutputCallback

I figured out a solution.

The VTCompressionSessionCreate call has a parameter for outputCallbackRefCon which gets passed along to the VTCompressionOutputCallback.

By wrapping self in an UnsafeMutableRawPointer like so

let unmanagedSelf = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())

I was able to pass that value into the VTCompressionSessionCreate under the refcon parameter. Inside of the callback I was then able to do pull that value back out using

let scopedSelf = Unmanaged<ViewController>.fromOpaque(unmanagedSelf).takeUnretainedValue()

How do I add a callback to a func that contains a dispatch_after()?

You do do not need to "pass" sender to the closure. You only need to reference sender inside the closure.

This is known as capture, and it is one of the useful things about closures. The closure will capture a reference to sender and take it with it. It's like magic.

So write the closure somewhere where sender is in scope. Reference sender inside the closure. Then, pass the closure to delay and everything should work fine:

func closeAlert(sender: UIVewController) {

let closure: () -> () = {
doSomethingWith(sender)
}

delay(3, closure: closure)
}

Again, the secret is that the closure captures a reference to sender that gets carried along with it when the closure gets passed to delay.

swift @objc and selector : compiler error with type returned from selector

Only global functions or closures (which capture no context) can be passed to the C function for the callback arguments. Similarly as in How to use instance method as callback for function which takes only func or literal closure you can “tunnel” self (the pointer to the instance) to the callback functions by converting it to a void pointer and back. The callback function can then call the instance method:

class VLCStreamProcessor {
func lock_frame(
planes: UnsafeMutablePointer<UnsafeMutableRawPointer?>?)
-> UnsafeMutableRawPointer?
{ // ...
}

func unlock_frame(
picture: UnsafeMutableRawPointer?,
planes: UnsafePointer<UnsafeMutableRawPointer?>?)
{ // ...
}

func myVLCProcessing() {
// ...

let opaque = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
libvlc_video_set_callbacks(mplayerPtr, { (opaque, planes) -> UnsafeMutableRawPointer? in
let mySelf = Unmanaged<VLCStreamProcessor>.fromOpaque(opaque!).takeUnretainedValue()
return mySelf.lock_frame(planes: planes)
}, { (opaque, picture, planes) in
let mySelf = Unmanaged<VLCStreamProcessor>.fromOpaque(opaque!).takeUnretainedValue()
mySelf.unlock_frame(picture: picture, planes: planes)
}, nil, opaque)

}
}

Here it is assumed that the VLCStreamProcessor exists as long as the libvlc callbacks are set, otherwise the pointers have to be retained.



Related Topics



Leave a reply



Submit