Learn Courses My Dashboard

How to update status menu view periodically?

tl;dr: I want to update view so it reflects a variable. The variable changes both when the view is and when its not active.

I am making a status menu app and I need the view to update every second. I want to update the progressValue var in UtilityToolsView every so often even when the menu app isn’t selected and when the menu is selected I want the view to reflect the changes of progressValue . Aside from the view it self, I used this tutorial to make the status menu appear in the top bar (I am new to swiftUI/mac development and even though I am trying to fully understand the code, I don’t fully understand it): Building a macOS Menu Bar App - The Dad Jokes Series (Part 1) - YouTube

I have a function to get the CPU usage which I want to be called every second (or so) and set it to firstValue , but the view doesn’t update.


class ApplicationMenu: NSObject {
    let menu = NSMenu()
    func createMenu() -> NSMenu {
        let utilityToolsView = UtilityToolsView()
        let topView = NSHostingController(rootView: utilityToolsView)
        topView.view.frame.size = CGSize(width: 225, height: 225)
        let customMenuItem = NSMenuItem()
        customMenuItem.view = topView.view
        return menu;

AppDelegate + Main:

struct UtilityToolsApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        Settings {

class AppDelegate: NSObject, NSApplicationDelegate {
    static private(set) var instace: AppDelegate!
    lazy var statusBarItem = NSStatusBar.system.statusItem(withLength: 20)
    let menu = ApplicationMenu()
    func applicationDidFinishLaunching(_ notification: Notification) {
        AppDelegate.instace = self
        let image = NSImage(systemSymbolName: "gearshape.circle", accessibilityDescription: "A gear inside of a circle.")
        let config = NSImage.SymbolConfiguration(textStyle: .body, scale: .large)
        statusBarItem.button?.image = image?.withSymbolConfiguration(config)!
        statusBarItem.button?.imagePosition = .imageLeading
        statusBarItem.menu = menu.createMenu()

And then I have a basic view ( ProgressBar is a struct that creates the bar. I plan on having multiple):

struct UtilityToolsView: View {
    @State var firstValue: Float = 0

    var body: some View {
        VStack(spacing: 0) {
            HStack(alignment: .center, spacing: 15) {
                ProgressBar(progress: self.$firstValue)
            }.padding(15).padding([.bottom], 0)

I have tried to add a .task {} with a timer to the view, but it only updates when I don’t have it selected. I thought of defining firstValue outside of the view (updating it periodically there) and then giving it to the view, but I don’t know if that even makes sense and I don’t know how.