3
votes

I'm watching the Stanford Swift lecturers on ItunesU and have some trouble in understanding.

The lecturer is typecasting a String to a Double at one point. He did it as follows:

return NSNumberFormatter().numberFromString(display.text!)!.doubleValue

display.text is a UILabel Anyhow, when I'm doing it like this my app crashes and I get the following error:

fatal error: unexpectedly found nil while unwrapping an Optional value

When I typecast the String like this:

(display.text! as NSString).doubleValue

it works fine.

I know there must be an optional var anywhere but I'm not that into it to say what is wrong at this point.

8

8 Answers

5
votes

The issue is your display.text doesn't have a valid number in it's text. So it'll return nil.

So your expression will become:

return nil!.doubleValue

And it'll definitely crash.

For converting a String to double your second approach is more suitable. Means using:

(display.text! as NSString).doubleValue

is a better approach for this case.


Reference : NSNumberFormatter Class Reference

- numberFromString:

Returns an NSNumber object created by parsing a given string.

Declaration

Swift

func numberFromString(_ string: String) -> NSNumber?

Objective-C

- (NSNumber *)numberFromString:(NSString *)string

Parameters

string

An NSString object that is parsed to generate the returned number object.

Return Value

An NSNumber object created by parsing string using the receiver’s format. Returns nil if there are no numbers in the passed string.

Discussion

Any leading spaces in a string are ignored. For example, the strings “ 5” and “5” are handled in the same way.

3
votes

Mika, I just figured out why my calculator program is crashing with the same error message as you. Remember when we created the enter key, it was still "bound" to the appendDigit function and we had to option/right click on the button to break the connection. I was fighting the same issue as you, and it turned out that I had copy/pasted my operation keys and all of them were still connected to the appendDigit function. That meant every time I hit the "x" key, it was sending a non-number to the appendDigit function which when unwrapped was the equivalent of "nil". Hope that helps. Wilton

1
votes

In the first form, numberFromString returns nil if display.text does not contain a number.

My guess is that in this first case your display.text is not initialized with a number. So numberFromString return a nil that you are trying to unwrap using !. This throw the error.

In the second form, you are typecasting as NSString no matters what is the content (empty, "1.0", "foo"...) and then calling doubleValue which will return 0.0 if the string doesn’t begin with a valid text (different than a number).This doesn't throw an error, in the worst case it will return 0.0.

1
votes

I'm currently following the lectures and ran into the same issue. user3763062 and I had the same problem: we both accidentally left the enter key bounded to appendDigit function.

Deleting the connection solved my issue.

1
votes

Well, I guess you learning the Swift programming and making your first calculator. If I'm right, you getting this crash because you forgot to delete a message that your Enter button sending. In this case you getting an error because Enter symbol does not represent a number.

1
votes

I was running into the same issue when I tested the app on my iPhone. The problem was the dot, for decimal numbers. My iPhone region was set to Romania, where we use comma to separate decimals and I believe the numberFromString depends on the region when making transformations. After I changed the region to US, the nil exception did not appear.

0
votes

You can use a conditional cast to Double and nil coalescing operator to make sure it does't return nil as follow:

var myNumber = NSNumberFormatter().numberFromString("10.5") as? Double ?? 0
println(myNumber)   // 10.5

myNumber = NSNumberFormatter().numberFromString("10") as? Double ?? 0
println(myNumber)   // 10.0

myNumber = NSNumberFormatter().numberFromString("abc") as? Double ?? 0
println(myNumber)   // 0.0
0
votes

For me, this works:

return Double(display.text!)!