問題は、それIOPowerSourceCallbackType
がC 関数であることです。
Apple のドキュメントによると、これらの関数はクロージャーとして利用できます。
C 関数ポインターは、C 関数ポインター呼び出し規則を使用してクロージャーとして Swift にインポートされます。
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)
2 番目のオプションは、トップレベル関数を使用することです。
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")
}
}
ボーナス
CFunction ポインタに関する関連記事