Reputation: 14953
I'm trying to create a menubar app that will update the word shown in the menubar every 10 minutes. But at the moment it is just showing KBar initially instead of being set to a random word immediately:
import SwiftUI
@main
struct KBarApp: App {
var database = Database()
@State private var heading = "KBar" // Initial title in the menu bar
// Function to update the title every 10 minutes
func startTimer() {
Timer.scheduledTimer(withTimeInterval: 600, repeats: true) { _ in
let word = database.randomWord() // Always returns a word
heading = word.korean // Update heading to the new word
print("Timer updated heading: \(heading)") // Debug: print the new heading
}
}
// Initialize the database and fetch a random word when the app starts
init() {
database = Database() // Initialize the database
let word = database.randomWord() // Get initial random word
heading = word.korean // Set the initial heading
print("Initial heading: \(heading)") // Debug: print initial heading
}
var body: some Scene {
MenuBarExtra(LocalizedStringKey(heading)) {
ContentView()
.onAppear {
// Start the timer when the app starts
startTimer()
print("App appeared. Initial heading: \(heading)") // Debug: print when app starts
}
}
.menuBarExtraStyle(.window)
}
}
Upvotes: 1
Views: 41
Reputation: 273540
You should not set @State
properties in the init
of your App
. SwiftUI is not yet ready to handle @State
changes in this point yet.
The onAppear
attached to ContentView
will also not be called until after the user opens the menu bar extra. That's the first time ContentView
appears.
If you pass a label: { ... }
argument to the MenuBarExtra
instead of just a LocalizedStringKey
, you can write Text(heading).onAppear { ... }
, and this onAppear
will be called.
Here is an example of the menu bar extra title changing every one second. I have used a task
instead of a Timer
.
let words = ["Foo", "Bar", "Baz", "Apple", "Orange", "Peach"]
@State var title = "Foo"
MenuBarExtra {
ContentView()
} label: {
Text(title)
.task {
do {
while true {
title = words.randomElement()!
try await Task.sleep(for: .seconds(1))
}
} catch {
// task has been cancelled
}
}
}
.menuBarExtraStyle(.window)
Upvotes: 0