-1

I have just started learning the basics of swift and was playing around with swiftui to make a calculator to get the hang of it. However, I keep getting the error that a nil value is being found while trying to force unwrap a variable. I understand that using forced unwrap isn't safe practice, so I tried to replace it with if let statements, but those just make my calculation result become 0, i.e it never enters the if let statement. The logic of my code is in the picture, any help would be really appreciated.

code that crashes the app due to unexpected nil

import SwiftUI

struct ContentView: View {
    @State private var firstnumber = 0
    @State private var secondnumber = 0
    @State private var operand = ""
    @State private var calctext = "0"
    @State private var isTyping = false

    var body: some View {
        ZStack { Color.black
            .edgesIgnoringSafeArea(.all)
            VStack(){
            TextField("0", text: $calctext)
                .padding(EdgeInsets(top: 150, leading: 20, bottom: 20, trailing: 20))
                .border(Color.gray, width: 2)
                .multilineTextAlignment(.trailing)
                .foregroundColor(Color.white)
                .font(.largeTitle)



            HStack{
                createbutton("AC")
                .buttonStyle(numberdesign1())
                Spacer()
                createbutton("+/-")
                .buttonStyle(numberdesign1())
                Spacer()
                createbutton(" % ")
                .buttonStyle(numberdesign1())
                Spacer()
                Button(action: {
                    self.operandclick("÷")
                }) {
                Text(" ÷ ")
                }
                .buttonStyle(buttondesign())
                .cornerRadius(15.0)
            }.padding()

            HStack{
                createbutton(" 9 ")
                .buttonStyle(numberdesign())
                Spacer()
                createbutton(" 8 ")
                .buttonStyle(numberdesign())
                Spacer()
                createbutton(" 7 ")
                .buttonStyle(numberdesign())
                Spacer()
                Button(action: {
                    self.operandclick("×")
                }) {
                Text(" × ")
                }
                .buttonStyle(buttondesign())
                .cornerRadius(15.0)
            }.padding()

            HStack{
                createbutton(" 6 ")
                .buttonStyle(numberdesign())
                Spacer()
                createbutton(" 5 ")
                .buttonStyle(numberdesign())
                Spacer()
                createbutton(" 4 ")
                .buttonStyle(numberdesign())
                Spacer()
                Button(action: {
                    self.operandclick("-")
                }) {
                Text(" - ")
                }
                .buttonStyle(buttondesign())
                .cornerRadius(15.0)
            }.padding()

            HStack{
                createbutton(" 3 ")
                .buttonStyle(numberdesign())
                Spacer()
                createbutton(" 2 ")
                .buttonStyle(numberdesign())
                Spacer()
                createbutton(" 1 ")
                .buttonStyle(numberdesign())
                Spacer()
                Button(action: {
                    self.operandclick("+")
                }) {
                Text(" + ")
                }
                .buttonStyle(buttondesign())
                .cornerRadius(15.0)

            }.padding()

            HStack{
                Button(action: {
                    self.digitTapped("0")

                }) {
                    Text(" 0                           ")
                }
                .foregroundColor(Color.white)
                .padding(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
                .background(Color.gray)
                .border(Color.gray, width: 1)
                .cornerRadius(40.0)
                Spacer()
                createbutton("  .  ")
                .buttonStyle(numberdesign())
                Spacer()
                Button(action: {
                    self.calculate()
                }) {
                Text(" = ")
                }
                .buttonStyle(buttondesign())
                .cornerRadius(15.0)

            }.padding()



            }
            .aspectRatio(contentMode: .fill)

        }
    }

    private func createbutton(_ number: String) -> Button<Text> {
        return Button(action: {
            self.digitTapped(number)
        }) {
            (Text(number))
        }
    }

    private func digitTapped(_ number: String) -> Void {
        if isTyping {
            calctext += number
        } else {
            calctext = number
            isTyping = true
        }
    }

    private func operandclick(_ operand: String) {
        isTyping = false
//        if Int(calctext) != nil {
        firstnumber = Int(calctext)!
//        }
        
        self.operand = operand
        calctext = operand
    }

    private func calculate() {
        isTyping = false
        var result = 0
//        if Int(calctext) != nil {
        secondnumber = Int(calctext)!
//        }
        

        if operand == "+" {
            result = firstnumber + secondnumber
            print (result, firstnumber, secondnumber)
        } else if operand == "-" {
            result = firstnumber - secondnumber
        } else if operand == "÷" {
            result = firstnumber / secondnumber
        } else if operand == "×" {
            result = firstnumber * secondnumber
        }

        calctext = "\(result)"
    }
}




struct buttondesign: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundColor(Color.white)
            .padding()
            .background(LinearGradient(gradient: Gradient(colors: [Color("DarkGreen"),Color("LightGreen")]), startPoint: .leading, endPoint: .trailing))
        .clipShape(Circle())
    }
}

struct numberdesign: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
        .foregroundColor(Color.white)
            .padding(.all)
        .background(Color.gray)
        .border(Color.gray, width: 1)
            .clipShape(Circle().scale(1))

    }
}

struct numberdesign1: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
        .foregroundColor(Color.black)
        .padding(.all)
        .background(Color("LightGray"))
        .border(Color.gray, width: 1)
        .clipShape(Circle())

    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }

}
  • What is in `calctext` at the time of the crash? – vacawama Jul 21 '20 at 22:49
  • You should post the code itself instead of pictures of code. This allows people to try your code by pasting it into a project or Playground, and it allows the code to show up in searches on StackOverflow. – vacawama Jul 21 '20 at 22:50
  • BTW: An operator is the 'function' that performs the operation, whereas the operand is the input to that function. In the expression 3 + 4 = 7, the operator is '+' - since it's telling us how to perform the operation - and the operands are 3 and 4 - the inputs upon which the operation is acting. – vacawama Jul 21 '20 at 22:56
  • Hi, `calctext` contains nil at the time of the crash for some reason that I cant understand. I tried posting my code on the original post but it kept giving me formatting errors. I will update my post with the code itself right now, and thanks for the tip! I didn't notice I had named the wrong thing operands. – Hritik Raj Jul 22 '20 at 01:13
  • It can’t be nil, it’s a String. When it crashes, print the value of calctext in the debugger. – vacawama Jul 22 '20 at 01:21
  • Hi, I'm probably missing something, but this is the output the debugger gives error: Couldn't lookup symbols: Calculator.ContentView.(calctext in _4B188E24C2892DA9E563DDA8148EE866).getter : Swift.String. I am lost as to how to interpret this – Hritik Raj Jul 22 '20 at 01:36
  • Try this. Add `print(calctext)` before the lines where you do `Int(calctext)` and you should see it in the console. – vacawama Jul 22 '20 at 01:40
  • Hi, I did that, and it printed 87 on the console, which is the number I entered into the app simulator. I was trying to multiply 87 with a number, but as soon as I pressed the multiplication sign, it crashed. – Hritik Raj Jul 22 '20 at 01:46
  • I bet your string has spaces in it. Make sure to only put digits in it. – vacawama Jul 22 '20 at 01:51
  • Thank you so much that worked! I did not even consider that it could be causing the problem! I had initially added those spaces to make the button size bigger because I did not know how to manipulate the size of the circular buttons. I really appreciate your help! – Hritik Raj Jul 22 '20 at 02:12

2 Answers2

0

Make sure your String does not have space as its unable to convert it to integer and will return nil and if you force Cast this it will crash

Jawad Ali
  • 13,556
  • 3
  • 32
  • 49
0

You should not force unwrap optionals unless you are sure that they don't contain any nil values.

I would suggest you to use nil coalescing operator to provide default value to the integer conversion from string

let firstNumber = Int(calcText) ?? 0
Jarvis The Avenger
  • 2,750
  • 1
  • 19
  • 37