开发可定时更新的MacOS 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
相关产品推荐
相关产品推荐

