You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发可定时更新的MacOS MenuBarExtra应用遇问题求助

修复MacOS SwiftUI MenuBarExtra秒数计数问题

问题根源

  • Timer的事件监听绑定在了菜单内的Text组件上,只有菜单展开时该组件才会被渲染,导致计数仅在菜单打开时生效。
  • MenuBarExtra的标题直接使用字符串插值"\(store.workedSeconds)",这种写法无法响应@Published属性的变化,标题不会自动更新。

解决方案

方案一:在App层级处理Timer

将Timer的监听逻辑移到MenuBarExtra外部,确保应用启动后Timer持续运行,同时用Text作为MenuBarExtra的标题,利用SwiftUI的自动刷新机制更新显示:

import SwiftUI

class ThirdTimerStore: ObservableObject {
    @Published var workedSeconds: Int = 0
}

@main
struct Third_TimerApp: App {
    @StateObject var store = ThirdTimerStore()
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    
    var body: some Scene {
        MenuBarExtra {
            Text("Time: \(store.workedSeconds)")
        } label: {
            Text("\(store.workedSeconds)")
        }
        .onReceive(timer) { _ in
            store.workedSeconds += 1
        }
    }
}

方案二:将Timer逻辑封装到ObservableObject(推荐)

把Timer的创建和管理逻辑放到ThirdTimerStore类中,让状态与逻辑内聚,App代码更简洁:

import SwiftUI
import Combine

class ThirdTimerStore: ObservableObject {
    @Published var workedSeconds: Int = 0
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        Timer.publish(every: 1, on: .main, in: .common)
            .autoconnect()
            .sink { [weak self] _ in
                self?.workedSeconds += 1
            }
            .store(in: &cancellables)
    }
}

@main
struct Third_TimerApp: App {
    @StateObject var store = ThirdTimerStore()
    
    var body: some Scene {
        MenuBarExtra {
            Text("Time: \(store.workedSeconds)")
        } label: {
            Text("\(store.workedSeconds)")
        }
    }
}

说明

两种方案都能实现每秒递增的计数功能,且菜单标题和内部文本都会实时更新。方案二更符合MVVM架构,将业务逻辑封装在数据模型中,便于后续扩展维护。

内容的提问来源于stack exchange,提问作者exclipy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 00:52:22