SwiftUI Timer not working inside Menu bar extra

Hello,

I am new to the Swift and the SwiftUI. I want to build a MacOS app for learning purpose. Looks like I am stuck, so looking for some help.

The code below does not execute the print statement. Why is the timer not working? What am I missing? Thanks in advance.

struct CustomView: View {    
    let timer = Timer.publish(every: 1, on: .current, in: .common).autoconnect()
    private var nums: [String] = ["one", "two"]    

    var body: some View {
        ForEach(nums, id: \.self) {num in
            Text(num)
        }
        .onReceive(timer) { time in
            // why is this not working?
            print("time is \(time)")
        }
    }
}

@main struct Writer: App {
    var body: some Scene {
        MenuBarExtra("Writer util", systemImage: "pencil.line") {
            CustomView()
        }
        .menuBarExtraStyle(.menu)
    }
}

Change .menuBarExtraStyle(.menu) to .menuBarExtraStyle(.window)

I need a menu and not a window. Anyways, the change works! Care to explain why .menu doesn't work and .window does?

Care to elaborate why it doesn't work for .menu and works for .window? For my use case, I need the .menu.

Can someone please help, here?

You should read the document of the Timer. The timer need to run in a runloop, which Window has but menu hasn't. So if you want to use a timer inside the menu, you may need to create a runloop and add the timer to it. That might work.

Using a dedicated obervable object with a timer being initialized there will perfectly work while the open menu is blocking the runloop from SwiftUI.

public final class MyObject: ObservableObject {
	@Published var showItem: Bool = false
	
	var cancellable = Set<AnyCancellable>()
	
	init() {
		Timer.publish(every: 5, on: .main, in: .common)
			.autoconnect()
			.sink(receiveValue: { [weak self] value in
				print(value)
				self?.showItem = true
			})
			.store(in: &cancellable)
	}
}

And within the MenuBarExtra content closure, you can use something like:

if myObject.showItem{
  Button("Item 2") {
						
  }
}
SwiftUI Timer not working inside Menu bar extra
 
 
Q