gpt4 book ai didi

swift - 在 Swift 中使用 IOPSNotificationCreateRunLoopSource 创建一个 CFRunLoopSourceRef

转载 作者:搜寻专家 更新时间:2023-10-31 22:31:53 27 4
gpt4 key购买 nike

我正在尝试订阅 macOS 上电源状态的变化。我发现有一种使用 IOKit 的方法,尽管它有点复杂。我需要使用 #import <IOKit/ps/IOPowerSources.h> 导入它在 ObjC 桥接 header 中。然后我可以访问具有签名的函数 IOPSNotificationCreateRunLoopSource:

IOPSNotificationCreateRunLoopSource(_ callback: IOPowerSourceCallbackType!, _ context: UnsafeMutablePointer<Void>!) -> Unmanaged<CFRunLoopSource>!

我从 Callback method to Apple run loop 中的答案中得到了一些帮助, 但仍然无法创建 IOPowerSourceCallbackType 类型的函数在 swift 。这个编译缺少的部分是什么?

最佳答案

问题是 IOPowerSourceCallbackType 是一个 C 函数

根据 Apple 的文档,这些函数可以作为闭包使用:

C function pointers are imported into Swift as closures with C function pointer calling convention

https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-ID148

所以最简单的方法是使用闭包:

IOPSNotificationCreateRunLoopSource({ (context: UnsafeMutableRawPointer?) in
debugPrint("Power source changed")
}, &context)

第二种选择是使用顶级函数:

func powerSourceChanged(arg: UnsafeMutableRawPointer?) {
debugPrint("Power source changed")
}
IOPSNotificationCreateRunLoopSource(powerSourceChanged, &context)

引用我如何使用它的完整实现:​​

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 不是指针。

当你尝试通过在 & (&self) 前添加指针来传递 self 时,你会得到一个错误,self 是不可变的。

要将其转换为不透明指针,您可以使用 Unmanaged 类:

let opaque = Unmanaged.passRetained(self).toOpaque()

然后可以用作 UnsafeMutableRawPointer:

let context = UnsafeMutableRawPointer(opaque)

我们可以将什么用作 IOPSNotificationCreateRunLoopSource 的上下文。

然后在回调中,通过再次使用 Unmanaged 类,我们可以将此指针解析回其初始实例:

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")
}
}

奖金

A related article about CFunction pointers

关于swift - 在 Swift 中使用 IOPSNotificationCreateRunLoopSource 创建一个 CFRunLoopSourceRef,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38057615/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com