Skip to content

Efficiency Refactor: Event-Driven BatteryManager (No More Polling!) #82

@qusaismael

Description

@qusaismael

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions