Swift - CPU 使用率未更新

问题描述 投票:0回答:1

我编写了 SwiftUI 代码,它使用组合来显示系统上每个核心的 CPU 使用率指标,例如

User
System
Nice
Idle
值。该功能最初的作用是在应用程序启动时,正确获取并显示使用数据。

但是,我遇到了一个问题:初始数据显示后,数值并没有按照我的预期实时更新。第一次获取后,Combine 发布者似乎停止触发更新,并且 UI 中没有反映任何新数据。

我正在寻找有关如何使值连续或定期刷新的指导。也许我在组合的设置方式中遗漏了一些东西,或者也许有一种更有效的方法来保持 UI 与实时数据更新。

任何建议或见解将不胜感激。预先感谢!

这是我的代码:

import SwiftUI
import Combine

struct ContentView: View {
    
    @StateObject private var cpuMonitor = CPUUsageMonitor()
    
    var body: some View {
        ScrollView {
            VStack {
                Text("Overall CPU Usage")
                    .font(.largeTitle)
                    .padding()

                ForEach(0..<cpuMonitor.cpuUsages.count, id: \.self) { index in
                    VStack(alignment: .leading) {
                        Text("Core \(index):")
                            .font(.headline)

                        HStack {
                            Text("User: ")
                            Text("\(cpuMonitor.cpuUsages[index].user, specifier: "%.2f")%")
                        }
                        HStack {
                            Text("System: ")
                            Text("\(cpuMonitor.cpuUsages[index].system, specifier: "%.2f")%")
                        }
                        HStack {
                            Text("Nice: ")
                            Text("\(cpuMonitor.cpuUsages[index].nice, specifier: "%.2f")%")
                        }
                        HStack {
                            Text("Idle: ")
                            Text("\(cpuMonitor.cpuUsages[index].idle, specifier: "%.2f")%")
                        }
                    }
                    .padding()
                }
            }
        }
        .onAppear {
            cpuMonitor.startMonitoring()
        }
        .onDisappear {
            cpuMonitor.stopMonitoring()
        }
    }
}

class CPUUsageMonitor: ObservableObject {
    @Published var cpuUsages: [CoreUsage] = []

    private var cpuInfo: processor_info_array_t!
    private var prevCpuInfo: processor_info_array_t?
    private var numCpuInfo: mach_msg_type_number_t = 0
    private var numPrevCpuInfo: mach_msg_type_number_t = 0
    private var numCPUs: uint = 0
    private var timerCancellable: AnyCancellable?

    init() {
        let mibKeys: [Int32] = [CTL_HW, HW_NCPU]
        mibKeys.withUnsafeBufferPointer { mib in
            var sizeOfNumCPUs: size_t = MemoryLayout<uint>.size
            let status = sysctl(processor_info_array_t(mutating: mib.baseAddress), 2, &numCPUs, &sizeOfNumCPUs, nil, 0)
            if status != 0 {
                numCPUs = 1
            }
        }
        cpuUsages = Array(repeating: CoreUsage(user: 0.0, system: 0.0, nice: 0.0, idle: 0.0), count: Int(numCPUs))
    }

    func startMonitoring() {
        timerCancellable = Timer.publish(every: 1, on: .main, in: .common)
            .autoconnect()
            .sink { [weak self] _ in
                self?.updateInfo()
            }
    }

    func stopMonitoring() {
        timerCancellable?.cancel()
    }

    func updateInfo() {
        var numCPUsU: natural_t = 0
        var cpuLoadInfo: processor_info_array_t!
        var cpuLoadInfoCount: mach_msg_type_number_t = 0
        let err: kern_return_t = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numCPUsU, &cpuLoadInfo, &cpuLoadInfoCount)
        
        if err == KERN_SUCCESS {
            var updatedUsages: [CoreUsage] = []

            for i in 0..<Int32(numCPUs) {
                let userTicks = cpuLoadInfo[Int(CPU_STATE_MAX * i + CPU_STATE_USER)]
                let systemTicks = cpuLoadInfo[Int(CPU_STATE_MAX * i + CPU_STATE_SYSTEM)]
                let niceTicks = cpuLoadInfo[Int(CPU_STATE_MAX * i + CPU_STATE_NICE)]
                let idleTicks = cpuLoadInfo[Int(CPU_STATE_MAX * i + CPU_STATE_IDLE)]

                let total = userTicks + systemTicks + niceTicks + idleTicks
                let userUsage = Float(userTicks) / Float(total) * 100
                let systemUsage = Float(systemTicks) / Float(total) * 100
                let niceUsage = Float(niceTicks) / Float(total) * 100
                let idleUsage = Float(idleTicks) / Float(total) * 100

                let coreUsage = CoreUsage(user: userUsage, system: systemUsage, nice: niceUsage, idle: idleUsage)
                updatedUsages.append(coreUsage)
            }

            DispatchQueue.main.async {
                self.cpuUsages = updatedUsages
            }

            // Deallocate previous CPU info
            if let prevCpuInfo = prevCpuInfo {
                let prevCpuInfoSize: size_t = MemoryLayout<integer_t>.stride * Int(numPrevCpuInfo)
                vm_deallocate(mach_task_self_, vm_address_t(bitPattern: prevCpuInfo), vm_size_t(prevCpuInfoSize))
            }

            // Store the current info for future deallocation
            prevCpuInfo = cpuLoadInfo
            numPrevCpuInfo = cpuLoadInfoCount
        } else {
            print("Error gathering CPU info!")
        }
    }
}

struct CoreUsage {
    var user: Float
    var system: Float
    var nice: Float
    var idle: Float
}

#Preview {
    ContentView()
}
swift swiftui cpu combine foundation
1个回答
0
投票

您对

ticks
的计算不正确,这就是您得到错误值的原因。您必须正确考虑
prevCpuInfo

let userTicks = cpuLoadInfo[Int(CPU_STATE_MAX * i + CPU_STATE_USER)] - (prevCpuInfo?[Int(CPU_STATE_MAX * i + CPU_STATE_USER)] ?? 0)
let systemTicks = cpuLoadInfo[Int(CPU_STATE_MAX * i + CPU_STATE_SYSTEM)] - (prevCpuInfo?[Int(CPU_STATE_MAX * i + CPU_STATE_SYSTEM)] ?? 0)
let niceTicks = cpuLoadInfo[Int(CPU_STATE_MAX * i + CPU_STATE_NICE)] - (prevCpuInfo?[Int(CPU_STATE_MAX * i + CPU_STATE_NICE)] ?? 0)
let idleTicks = cpuLoadInfo[Int(CPU_STATE_MAX * i + CPU_STATE_IDLE)] - (prevCpuInfo?[Int(CPU_STATE_MAX * i + CPU_STATE_IDLE)] ?? 0)

Combine 发布者似乎在第一次获取后停止触发更新,并且 UI 中没有反映新数据。

我无法重现此问题,并且您的代码在这方面似乎没有任何错误。

© www.soinside.com 2019 - 2024. All rights reserved.