Learning Class Initializers and Calling in Button Actions

I'm still a beginner in SwiftUI so there is probably a better way to do this, but basically what I want to do is have a form of code length management where I have all these different buttons in my app that do the same thing. So naturally I want to create a method to call in each button action so I don't have to copy and paste the action every time.

This is the method I created:

class NumberButtonLogic {
    var operation : Int
    var tempOp    : Int
    var output    : String
    var temp      : String
    var buttonNum : Int

    init(operation: Int, tempOp: Int, output: String, temp: String, buttonNum: Int) {
        self.operation = operation
        self.tempOp    = tempOp
        self.output    = output
        self.temp      = temp
        self.buttonNum = buttonNum
    }

    func runLogic() {
        if operation != 0 {
            if output == "0." {
            } else {
                output = ""
            }
            tempOp = operation
            operation = 0
        }

        if output == "0" || output == "0.0" {
            if temp != "" {
            } else {
                output = ""
            }
        }

        output += String(buttonNum)

    }

}

Don't worry too much about the functionality of the runLogic() function, it's a mess, I know lol. But I basically want to have the different vars at the top be changed in runLogic().

From there, I go to a separate View area and create a new button:

    @State private var output: String = "0"
    @State private var operation: Int = 0
    @State private var temp: String = ""
    @State private var tempOp: Int = 0

    var numButton1 : NumberButtonLogic {
        NumberButtonLogic(operation: operation, tempOp: tempOp, output: output, temp: temp, buttonNum: 1)
    }

    Button {
        numButton1.runLogic()
        } label: {
        Text("1")
        }.buttonStyle(numberStyle())

Again don't worry about the numberStyle() style, it is working in the preview, so I don't think that's the issue with my code.

Basically what I want to do is display the number "1" on the screen when the button is pressed (but format it differently depending on what is already there). Also everything in the second code block I gave is in the struct ContentView : View {}.

Right now, when I press the button, I don't get any output, and the += modifier for output doesn't add the number "1" to the end of the string. However, if I put the code from the runLogic() function directly inside the button action, it runs fine. I hope that makes sense and thanks for your help!

Welcome to the forum.

I hope I understand what you expect.

  • The key issue is:
    var numButton1 : NumberButtonLogic {
        NumberButtonLogic(operation: operation, tempOp: tempOp, output: output, temp: temp, buttonNum: 1)
    }
  • You recompute the var each time you access, hence reinitialising it.

  • So, you should have an explicit init (declare the numButton1 var as implicit unwrapped(for the compiler to wait until int is run to get the content).

    var numButton1 : NumberButtonLogic!
    
    init() {
        numButton1 = NumberButtonLogic(operation: operation, tempOp: tempOp, output: output, temp: temp, buttonNum: 1)
        }
  • I changed as follows and seems to do what you expected (I instrumented with some print to check what is going on):
class NumberButtonLogic {
    var operation : Int
    var tempOp    : Int
    var output    : String
    var temp      : String
    var buttonNum : Int

    init(operation: Int, tempOp: Int, output: String, temp: String, buttonNum: Int) {
        self.operation = operation
        self.tempOp    = tempOp
        self.output    = output
        self.temp      = temp
        self.buttonNum = buttonNum
    }

    func runLogic() {
        if operation != 0 {
            if output == "0." {
                print("#1")
            } else {
                print("#2")
                output = ""
            }
            tempOp = operation
            operation = 0
        }
        
        if output == "0" || output == "0.0" {
            if temp != "" {
                print("#3")
            } else {
                print("#4")
                output = ""
            }
        }
        
        output += String(buttonNum)
        print("#5", output)
        
    }

}

struct ContentView: View { 
        @State private var output: String = "0"
        @State private var operation: Int = 0
        @State private var temp: String = ""
        @State private var tempOp: Int = 0
        
    var numButton1 : NumberButtonLogic!
    
    init() {
        numButton1 = NumberButtonLogic(operation: operation, tempOp: tempOp, output: output, temp: temp, buttonNum: 1)
        }
        
    var body: some View {

        Button {
            numButton1.runLogic()
            print(numButton1.output)
            output = numButton1.output
        } label: {
            Text("1")
        }
        
        Text(output)
    }
}

A general comment. Your understanding of how computed var work may be wrong.

You create a computed var to compute from other var. Such as in this toy example:

var distance: Double = 100.0 // The distance travelled
var duration: Double = 2.5     // The time needed

var speed: Double {
  if duration <= 0 { return 0 }  // avoid zero div result
  return distance / duration
}

Then in code, you may change distance and / or duration.

duration = 2.0
print(speed)

What happens:

  • when you call speed, it is calculated on the fly.
  • then the var speed "disappears"

So, you don't update an existing var, you compute a value on the fly.

In your code:

    var numButton1 : NumberButtonLogic {
        NumberButtonLogic(operation: operation, tempOp: tempOp, output: output, temp: temp, buttonNum: 1)
    }

you think you update an existing var. But in fact, you just create a momentary new instance, with initial parameters. No change.

Lesson:

  • a computed var is not to initialise a var.
  • note you should read (in Swift Programming language in Apple Book) the chapters about computed var and about getter and setter.
Learning Class Initializers and Calling in Button Actions
 
 
Q