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
Nsdate() or Date() Shows the Wrong Time
How Does String.Index Work in Swift
What Are the New "For", "At", "In" Keywords in Swift3 Function Declarations
How to Unwrap an Optional Value from Any Type
Custom Back Button For Navigationview'S Navigation Bar in Swiftui
Swift - Iboutletcollection Equivalent
Updating the Ui Using Dispatch_Async in Swift
How to Check If a Text Field Is Empty or Not in Swift
Selecting Global or Object Print Function
Overriding Methods in Swift Extensions
Why Is Swift Compile Time So Slow
Initialize @Stateobject With a Parameter in Swiftui
Xcode Swift Am/Pm Time to 24 Hour Format
What Does a Module Mean in Swift
How to Declare a Variable That Has a Type and Implements a Protocol