Home > Software design >  Unwrapped optional keeps refreshing / Working with optionals, arrays and randomElement()
Unwrapped optional keeps refreshing / Working with optionals, arrays and randomElement()

Time:09-21

I was wondering how you would approach making the following application work:

  • You have an array where you take a random element.
  • You make it multiply with a random number.
  • You have to input the answer and then whether or not you were right you get a score point.

Trying to make it work I stumbled upon the following problems:

  • When actually running the program every time the view was updated from typing something into the TextField, it caused the optional to keep getting unwrapped and therefor kept updating the random number which is not the idea behind the program.
  • How do I check whether or not the final result is correct? I can't use "myNum2" since it only exists inside the closure

Here's my code:

struct Calculate: View {
    
    @State var answerVar = ""
    @State var myNum = Int.random(in: 0...12)
    let numArray = [2,3,4,5] // this array will be dynamically filled in real implementation
    
    var body: some View {
        VStack {
            List {
                Text("Calculate")
                    .font(.largeTitle)
                
                HStack(alignment: .center) {
                    if let myNum2 = numArray.randomElement() {
                        Text("\(myNum) * \(myNum2) = ") // how can i make it so it doesn't reload every time i type an answer?
                    }
                    
                    TextField("Answer", text: $answerVar)
                        .multilineTextAlignment(.trailing)
                }
                
                HStack {
                    if Int(answerVar) == myNum * myNum2 { //how can i reuse the randomly picked element from array without unwrapping again?
                        Text("Correct")
                    } else {
                        Text("Wrong")
                    }
                    Spacer()
                    Button(action: {
                        answerVar = ""
                        myNum = Int.random(in: 0...12)
                    }, label: {
                        Text("Submit")
                            .foregroundColor(.white)
                            .shadow(radius: 1)
                            .frame(width: 70, height: 40)
                            .background(.blue)
                            .cornerRadius(15)
                            .bold()
                    })
                }
            }
        }
    }
}

CodePudding user response:

Move your logic to the button action and to a function to setupNewProblem(). Have the logic code change @State vars to represent the state of your problem. Use .onAppear() to set up the first problem. Have the button change between Submit and Next to control the submittal of an answer and to start a new problem.

struct Calculate: View {
    @State var myNum = 0
    @State var myNum2 = 0
    @State var answerStr = ""
    @State var answer = 0
    @State var displayingProblem = false
    @State var result = ""
    let numArray = [2,3,4,5] // this array will be dynamically filled in real implementation
    
    var body: some View {
        VStack {
            List {
                Text("Calculate")
                    .font(.largeTitle)
                
                HStack(alignment: .center) {
                    Text("\(myNum) * \(myNum2) = ")
                    
                    TextField("Answer", text: $answerStr)
                        .multilineTextAlignment(.trailing)
                }
                
                HStack {
                    Text(result)
                    
                    Spacer()
                    
                    Button(action: {
                        if displayingProblem {
                            if let answer = Int(answerStr) {
                                if answer == myNum * myNum2 {
                                    result = "Correct"
                                } else {
                                    result = "Wrong"
                                }
                                displayingProblem.toggle()
                            }
                            else {
                                result = "Please input an integer"
                            }
                        }
                        else {
                            setupNewProblem()
                        }
                            
                    }, label: {
                        Text(displayingProblem ? "Submit" : "Next")
                            .foregroundColor(.white)
                            .shadow(radius: 1)
                            .frame(width: 70, height: 40)
                            .background(displayingProblem ? .green : .blue)
                            .cornerRadius(15)
                            .bold()
                    })
                }
            }
        }
        .onAppear {
            setupNewProblem()
        }
    }
    
    func setupNewProblem() {
        myNum = Int.random(in: 0...12)
        myNum2 = numArray.randomElement()!
        result = ""
        answerStr = ""
        displayingProblem = true
    }
}
  • Related