skip to Main Content

Simplified example, I have a function that just takes a double as a parameter and increases that value by 1% and returns it. I have spent hours trying to get what I think is a pretty simple functionality but to no avail…

Now on my Content View I want to display the result of 100 being passed into that function AND refresh the calculation every second. e.g. pass in 100, after 1 second: return 101 to the TextView, after 2 seconds return: 102.01, 3 seconds: 103.03 …

I substituted my inc_by_one function call with a simple counter I increment by one with a state variable and it works as expected, i.e. updating every second, I’m mystified by why the inc_by_one function would perform any differently? Code below

My function:

func inc_by_one(dollar_amt: Double) -> Double {
    //increases the value provided by 1%
    return dollar_amt * 1.01
}

My ContentView:

import SwiftUI
import Combine

struct ContentView: View {
    
    @State private var theValue = 0.0  
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    
    var body: some View {
        VStack {
            
            Text("(theValue)")
                .onReceive(timer) { time in
                    theValue = inc_by_one(dollar_amt: 100)
                }

2

Answers


  1. When you call inc_by_one(dollar_amt: 100) you are passing 100 every time. So each time you call the function it multiplies 100 by 1.01.

    You need to pass the current value of theValue and you need to set theValue to 100.0 initially. You can also use a specifier to limit your output to 2 decimal places

    Also, a note on style _ isn’t very "Swifty" – Convention is to use camel case.

    import SwiftUI
    import Combine
    
    struct ContentView: View {
        
        @State private var theValue = 100.0  
        let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
        
        var body: some View {
            VStack {
                
                Text("(theValue, specifier:"%.02f")")
                    .onReceive(timer) { time in
                        theValue = incByOne(dollarAmt: 100)
                    }
            }
        }
    
        func incByOne(dollarAmt: Double) -> Double {
            return dollarAmt * 1.01
    }
    
    Login or Signup to reply.
  2. Try this approach, using a starting theValue = 100.0 and passing the
    theValue to the function, to achieve what you describe,
    ...after 1 second: return 101 to the TextView, after 2 seconds return: 102.01, 3 seconds: 103.03 ...

    struct ContentView: View {
        @State private var theValue = 100.0  // <-- here
        let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
        
        var body: some View {
            VStack {
                Text("(theValue)")
                    .onReceive(timer) { time in
                        theValue = inc_by_one(dollar_amt: theValue) // <-- here
                    }
            }
        }
        
        func inc_by_one(dollar_amt: Double) -> Double {
            //increases the value provided by 1%
            return dollar_amt * 1.01
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search