As said in the comments, you should always avoid using the 'crash operator' (!
) – and learn to safely deal with optional values instead.
Your program is crashing because either the titleLabel
, text
or Int(...)
are nil
– and you are then trying to force unwrap them. This could mean that your button doesn't have a titleLabel
or that titleLabel
's text isn't convertible to an Int
.
The solution is to safely deal with the optionals as you encounter them. There are many ways of doing this, but I usually like to use one or multiple guard
statements. This allows you to safely unwrap an optional if it has a value, otherwise it will execute the code within the brackets. This is useful for when future code depends on the optional not being nil
. For example:
guard let buttonText = sender.titleLabel?.text else {
print("Sender didn't have either a titleLabel or text!")
return
}
guard let textAsInt = Int(buttonText) else {
print("Text wasn't convertible to an Int!")
return
}
currentNumber = currentNumber*10 + Float(textAsInt)
Now you get helpful print
messages instead of crashes! Therefore you know exactly what went wrong, and what you can do to fix it (if it needs fixing).
You could also consolidate both of these checks into a single guard
if you want more concise code, but less precise errors:
guard let buttonText = sender.titleLabel?.text, textAsInt = Int(buttonText) else {
print("Something went wrong when converting the button title to an Int!")
return
}
currentNumber = currentNumber*10 + Float(textAsInt)
Or you can use flatMap
if you like closures:
guard let i = sender.titleLabel?.text.flatMap({Int($0)}) else {
print("Something went wrong when converting the button title to an Int!")
return
}
currentNumber = currentNumber*10 + Float(i)
The flatMap
option can look a bit weird at first, but all it's doing is attempting to convert the button's titleLabel
's text
to an Int
. If it fails it will return nil
(which the guard
will pick up), else it will return the numerical value of the text.
As @vacawama said in the comments, you could also use the nil coalescing operator in order to use 0
in the event that the titleLabel
, text
or Int(...)
are nil
:
currentNumber = currentNumber * 10 + Float(Int(sender.titleLabel?.text ?? "") ?? 0)
However bear in mind that this could lead to unexpected behaviour. I suspect that your program is crashing because your logic is getting run for non-numerical buttons, for example the "+" button. If this is the case, you'll be multiplying your number by 10
every time you press a non-numerical button. You'd have to first ensure that your logic only gets called on numerical buttons.
Although without seeing your full code, it's hard to say for sure.
For more info about how to safely deal with optionals, see this extensive Q&A on the subject.