2016-06-27 72 views
1

我正嘗試訂閱macOS上的電源狀態更改。我發現有一種使用IOKit的方法,雖然它有點複雜。我需要在ObjC橋接頭中使用#import <IOKit/ps/IOPowerSources.h>導入它。然後,我可以訪問功能IOPSNotificationCreateRunLoopSource,其中有簽名:在Swift中使用IOPSNotificationCreateRunLoopSource創建CFRunLoopSourceRef

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

我從回答一些幫助Callback method to Apple run loop,但仍然不管理創建IOPowerSourceCallbackType型的雨燕的功能。這個編譯缺失的是什麼?

+0

只是你知道;我爲我的答案增加了一個更廣泛的例子 –

回答

1

問題是IOPowerSourceCallbackType是一個C函數

根據蘋果的文檔,這些功能都可以關閉:

C函數指針被導入到斯威夫特與C函數指針調用約定封閉

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

UPDATE

要讓它與循環設置的實例進行交互,必須通過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 point的相關文章ers可以在這裏找到:

http://nshint.io/blog/2015/10/10/working-with-cfunction-pointers-in-swift/