-
-
Notifications
You must be signed in to change notification settings - Fork 12
Description
Goal
Refactor BatteryManager in Barik to be power-efficient by eliminating polling and switching to an event-driven model using IOKit notifications. This will greatly reduce unnecessary CPU usage and improve battery life.
Steps
Import IOKit
Add import IOKit
at the top of BatteryManager.swift.
Remove Polling Timer
Delete the Timer property and all related timer logic from start()
and stop()
.
Adopt Singleton Pattern
Make BatteryManager a singleton to ensure a single system-level listener.
static let shared = BatteryManager()
private override init() {
super.init()
// Setup logic goes here.
}
Create C-Style Callback
Add a static C-style function that will be triggered by IOKit on battery state changes:
private static func powerSourceChanged(context: UnsafeMutableRawPointer?) {
guard let context = context else { return }
let manager = Unmanaged<BatteryManager>.fromOpaque(context).takeUnretainedValue()
DispatchQueue.main.async {
manager.updatePowerState()
}
}
Implement State Update Logic
Add updatePowerState()
to fetch battery state via IOKit (IOPSCopyPowerSourcesInfo()
and IOPSGetPowerSourceDescription()
) and update all @Published
properties (capacity, isCharging, powerSource, etc.).
Register for System Events
In the private init()
, register the run loop source:
let loopSource = IOPSNotificationCreateRunLoopSource(
BatteryManager.powerSourceChanged,
Unmanaged.passUnretained(self).toOpaque()
).takeRetainedValue()
CFRunLoopAddSource(CFRunLoopGetCurrent(), loopSource, .defaultMode)
Fetch Initial State
Call updatePowerState()
in the init()
to immediately get the battery status on launch.
Outcome
- BatteryManager will be event-driven, using virtually zero resources when idle.
- The codebase will be simpler and easier to maintain.