PermissionCoordinator: probing macOS without freezing the UI
The 个人设置 screen used to stutter every second. Root cause: PermissionCoordinator was running 13 synchronous LaunchServices / EventKit / Accessibility probes on the main actor at 1 Hz. Diagnosis was easy; the fix is the part worth writing down.
Three changes, one fix
First, every probe became a nonisolated static helper — probeCalendar, probeReminder, probeAccessibility, probeAutomationItem, probeAutomationStatus. Second, refresh() now dispatches the entire batch onto Task.detached(.utility) and only hops back to MainActor to publish the diff. Third, polling backed off from 1 s to 5 s, with an isRefreshing coalescing flag so concurrent calls collapse.
| 1 | func refresh() { |
| 2 | guard !isRefreshing else { return } |
| 3 | isRefreshing = true |
| 4 | Task.detached(priority: .utility) { [weak self] in |
| 5 | let snap = Self.probeAll() |
| 6 | await MainActor.run { |
| 7 | self?.publishIfChanged(snap) |
| 8 | self?.isRefreshing = false |
| 9 | } |
| 10 | } |
| 11 | } |
Even one synchronous LaunchServices probe on the main thread stalls SwiftUI long enough to drop a frame. The general pattern: any system probe goes off-main; only the diff publish hops back.
Result
个人设置 reopen latency dropped from ~180 ms to instant; CPU at idle dropped to baseline. No change to public API — pure internal refactor.