SwiftUI 6.0.3开发Mac菜单栏CPU使用率显示问题求助
解决Mac菜单栏应用CPU使用率不更新的问题
问题根源分析
- 监控逻辑未启动:你定义了
startCPUMonitoring()但从未调用它,导致没有定时任务去更新CPU使用率,界面一直停留在默认的“Calculating...”。 - 使用率计算逻辑错误:单次调用
host_statistics拿到的是系统启动以来的累计CPU tick数,直接计算会得到错误的极低值(因为 idle 时间占比极大),必须通过两次采样的差值才能算出真实的实时使用率。 - Timer适配问题:直接用
Timer.scheduledTimer在SwiftUI App场景中容易出现运行循环适配问题,改用Swift Concurrency的异步任务更可靠。
修复后的完整代码
import SwiftUI import Foundation import MachO @main struct MenuBarApp: App { @State private var cpuUsage: String = "Calculating..." // 存储上一次采样的CPU tick数据 private var previousCPULoad: host_cpu_load_info_data_t? var body: some Scene { MenuBarExtra("icon \(cpuUsage)") { Button("Quit") { NSApp.terminate(nil) } } .onAppear { // 界面出现后启动CPU监控 Task { await startCPUMonitoring() } } } func startCPUMonitoring() async { while true { if let usage = await getCPUUsage() { cpuUsage = String(format: "%.1f%%", usage) } else { cpuUsage = "N/A" } // 每隔1秒更新一次 try? await Task.sleep(for: .seconds(1)) // 让出线程给其他任务 Task.yield() } } func getCPUUsage() async -> Double? { var size = mach_msg_type_number_t(MemoryLayout<host_cpu_load_info_data_t>.size / MemoryLayout<integer_t>.size) var cpuLoad = host_cpu_load_info_data_t() let result = withUnsafeMutablePointer(to: &cpuLoad) { $0.withMemoryRebound(to: integer_t.self, capacity: Int(size)) { host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, $0, &size) } } guard result == KERN_SUCCESS else { print("获取CPU负载失败: \(result)") return nil } // 第一次采样只存储数据,等待第二次采样计算差值 guard let previousLoad = previousCPULoad else { previousCPULoad = cpuLoad return nil } // 计算两次采样的差值 let userDiff = Double(cpuLoad.cpu_ticks.0 - previousLoad.cpu_ticks.0) let systemDiff = Double(cpuLoad.cpu_ticks.1 - previousLoad.cpu_ticks.1) let idleDiff = Double(cpuLoad.cpu_ticks.2 - previousLoad.cpu_ticks.2) let niceDiff = Double(cpuLoad.cpu_ticks.3 - previousLoad.cpu_ticks.3) let totalDiff = userDiff + systemDiff + idleDiff + niceDiff guard totalDiff > 0 else { previousCPULoad = cpuLoad return nil } // 计算使用率:(用户+系统+nice时间) / 总时间 * 100% let usage = (userDiff + systemDiff + niceDiff) / totalDiff * 100.0 previousCPULoad = cpuLoad return usage } }
关键修改说明
- 启动监控任务:通过
MenuBarExtra的onAppear回调启动异步任务,确保界面出现后立刻开始监控CPU。 - 差值计算逻辑:新增
previousCPULoad变量存储上一次的采样数据,通过两次tick的差值计算真实的实时使用率,这是解决数值错误的核心。 - 改用Swift Concurrency:用
Task.sleep替代传统Timer,更适配SwiftUI的异步环境,避免运行循环和生命周期问题。 - 显式导入MachO:确保Mach内核API的定义能被Xcode正确识别,避免编译警告或错误。
内容的提问来源于stack exchange,提问作者user28615420
相关产品推荐
相关产品推荐

