更新时间:2023-02-14 19:13:24
问题在于 IOPowerSourceCallbackType
是一个 C 函数.
The issue is that IOPowerSourceCallbackType
is a C function.
根据 Apple 的文档,这些函数可用作闭包:
According to Apple's documentation these functions are available as closures:
C 函数指针作为具有 C 函数指针调用约定的闭包导入到 Swift 中
C function pointers are imported into Swift as closures with C function pointer calling convention
所以最简单的方法是使用闭包:
So the easiest way is to use a closure:
IOPSNotificationCreateRunLoopSource({ (context: UnsafeMutableRawPointer?) in
debugPrint("Power source changed")
}, &context)
第二种选择是使用***函数:
A second option is to use a top-level function:
func powerSourceChanged(arg: UnsafeMutableRawPointer?) {
debugPrint("Power source changed")
}
IOPSNotificationCreateRunLoopSource(powerSourceChanged, &context)
参考我如何使用它的完整实现:
For reference the complete implementation of how I'm using this:
class WindowController: NSWindowController {
static var context = 0
override func windowDidLoad() {
super.windowDidLoad()
let loop: CFRunLoopSource = IOPSNotificationCreateRunLoopSource({ (context: UnsafeMutableRawPointer?) in
debugPrint("Power source changed")
}, &WindowController.context).takeRetainedValue() as CFRunLoopSource
CFRunLoopAddSource(CFRunLoopGetCurrent(), loop, CFRunLoopMode.defaultMode)
}
}
更新
要让它与设置循环的实例交互,您必须将 self
作为上下文传递,但是 self
不是指针.
To let it interact with the instance the loop was setup from, you have to pass self
as context, however self
isn't a pointer.
当你尝试通过在 &
(&self
) 前面加上 self
作为指针来传递它时,你会得到一个错误self
是不可变的.
When you try to pass self
as pointer by prepending it with &
(&self
), you'll get an error that self
is immutable.
要将其转换为不透明指针,您可以使用 Unmanaged
类:
To convert it a to an opaque pointer you can use the Unmanaged
class:
let opaque = Unmanaged.passRetained(self).toOpaque()
然后可以用作 UnsafeMutableRawPointer
:
let context = UnsafeMutableRawPointer(opaque)
我们可以用作IOPSNotificationCreateRunLoopSource
的上下文.
What we can use as the context for IOPSNotificationCreateRunLoopSource
.
然后在回调中,通过再次使用 Unmanaged
类,我们可以将此指针解析回其初始实例:
And then in the callback, by using the Unmanaged
class again, we can resolve this pointer back to its initiating instance:
let opaque = Unmanaged<WindowController>.fromOpaque(context!)
let _self = opaque.takeRetainedValue()
完整示例:
func PowerSourceChanged(context: UnsafeMutableRawPointer?) {
let opaque = Unmanaged<WindowController>.fromOpaque(context!)
let _self = opaque.takeRetainedValue()
_self.powerSourceChanged()
}
class WindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
let opaque = Unmanaged.passRetained(self).toOpaque()
let context = UnsafeMutableRawPointer(opaque)
let loop: CFRunLoopSource = IOPSNotificationCreateRunLoopSource(
PowerSourceChanged,
context
).takeRetainedValue() as CFRunLoopSource
CFRunLoopAddSource(CFRunLoopGetCurrent(), loop, CFRunLoopMode.defaultMode)
}
func powerSourceChanged() {
debugLog("Power source changed")
}
}
奖金