'How can you update a counting variable with a button and a timer simultaneously?

I am working on a cookie clicker like application but I am not able to make the currency to increase with both timer and button press simultaneously. I have the following code inside a view

class HomeView: View {
    @ObservedObject var currency: CurrencyTracker
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    
    var body: some View {
        VStack(alignment: .center, spacing: 16) {
            Text("$\(Int(floor(currency.amount)))")
                .font(.largeTitle)
            Button(action: {
                currency.amount += 1
            }) {
                Circle()
                    .foregroundColor(Color.red)
                    .frame(width: 80, height: 80)
            }
        }
        .padding(.all)
        .onReceive(timer, perform: { _ in
            currency.addCps()
        })
    }
}

CurrencyTracker class is defined as follows:

class CurrencyTracker: ObservableObject {

    @Published var amount: Double
    @Published var cps: Double
    
    init(amount: Double, cps: Double){
        self.amount = amount
        self.cps = cps
    }
    
    func addCps() {
        self.amount += self.cps
    }
}

If I start pressing my button rapidly multiple times, the timer triggered onReceive action does not run until I stop or press the button slowly. Any ideas on how I can work around this?



Solution 1:[1]

I just made your code compile – didn't change anything substantial – and this runs for me just fine. Clicking and timer do update simultaneously.

struct ContentView: View {
    @StateObject var currency = CurrencyTracker(amount: 0, cps: 1)
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    
    var body: some View {
        VStack(alignment: .center, spacing: 16) {
            Text("$\(Int(floor(currency.amount)))")
                .font(.largeTitle)
            Button(action: {
                currency.amount += 10
            }) {
                Circle()
                    .foregroundColor(Color.red)
                    .frame(width: 80, height: 80)
            }
        }
        .padding(.all)
        .onReceive(timer, perform: { _ in
            currency.addCps()
        })
    }
}

class CurrencyTracker: ObservableObject {

    @Published var amount: Double
    @Published var cps: Double
    
    init(amount: Double, cps: Double){
        self.amount = amount
        self.cps = cps
    }
    
    func addCps() {
        self.amount += self.cps
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ChrisR