Josh O'Connor
Josh O'Connor

Reputation: 4962

Unwrapping an Optional value which is nil

I am having a common error which involves optionals, and I have a NSUserDefault value which is the users location using the Location Manager Function:

func locationManager(manager: CLLocationManager!,
    didUpdateLocations locations: [AnyObject]!)
{

    //First Convert it to NSNumber.
    let lat : NSNumber = NSNumber(double: latestLocation.coordinate.latitude)
    let lng : NSNumber = NSNumber(double: latestLocation.coordinate.longitude)

    //Store it into Dictionary
    let locationDict = ["lat": lat, "lng": lng]

    //Store that Dictionary into NSUserDefaults
    NSUserDefaults.standardUserDefaults().setObject(locationDict, forKey: "Location")
}

When I run my app, it crashes at on the line let userLoc = NSUserDefaults... on the following code block in my viewDidLoad() method.

    let userLoc = NSUserDefaults.standardUserDefaults().objectForKey("Location") as! [String : NSNumber]

    //Grab location from that Dictionary (from func LocationManager below)
    let userLat = userLoc["lat"]
    let userLng = userLoc["lng"]

    //declare MKPointAnnotation()
    var Annotation = MKPointAnnotation()
    //Convert NSNumber to CLLocationDegrees
    Annotation.coordinate.latitude = userLat as! CLLocationDegrees
    Annotation.coordinate.longitude = userLng as! CLLocationDegrees

And the error is:

fatal error: unexpectedly found nil while unwrapping an Optional value.

I suspect this is because I havent stored the variable

NSUserDefaults.standardUserDefaults().objectForKey("Location") 

until AFTER the viewDidLoad method ran.

How do I avoid this error? Should I run the locationManager() function in my view did load?
I tried that it there was an error...

Any help would be GREATLY appreciated. I have been stuck on this for a few hours.

Josh

Upvotes: 0

Views: 215

Answers (3)

madjacamo
madjacamo

Reputation: 1

You must check if you are using a comma "," instead of a dot "." in the string that you are trying to cast to Double.

This throw nil error :

let latitude : CLLocationDegrees = Double("9,123")!   

This is the right way :

let latitude : CLLocationDegrees = Double("9.123")! 

Upvotes: -2

Paulw11
Paulw11

Reputation: 114773

You need to be careful when you use '!' to unwrap an optional or cast a value. This says "I know that this is not nil/an instance of this class and if it isn't, this is bad and throw an exception".

If there is a possibility that it is nil/not an instance of the desired class, then you should use '?' and act on the result appropriately.

if let userLoc = NSUserDefaults.standardUserDefaults().objectForKey("Location") as? [String : NSNumber] {

    //Grab location from that Dictionary (from func LocationManager below)
    let userLat = userLoc["lat"]
    let userLng = userLoc["lng"]

    //declare MKPointAnnotation()
    var Annotation = MKPointAnnotation()
    //Convert NSNumber to CLLocationDegrees
    Annotation.coordinate.latitude = userLat as! CLLocationDegrees
    Annotation.coordinate.longitude = userLng as! CLLocationDegrees
}

Your second use of '!' - when you assign the latitude/longitude to the coordinate is correct - If the cast doesn't succeed then there is something wrong with the data that you stored and crashing is probably a reasonable approach so that you can debug.

If the data was coming from some external source and could potentially be invalid the use of '?' and some sort of error handling could still be the better approach.

Upvotes: 4

Cai
Cai

Reputation: 3649

How about wrap it with a if statement if you are not sure whether it's still nil at that point?

if let userLoc = NSUserDefaults.standardUserDefaults().objectForKey("Location") as? [String : NSNumber] {

    //Grab location from that Dictionary (from func LocationManager below)
    let userLat = userLoc["lat"]
    let userLng = userLoc["lng"]

    //declare MKPointAnnotation()
    var Annotation = MKPointAnnotation()
    //Convert NSNumber to CLLocationDegrees
    Annotation.coordinate.latitude = userLat as! CLLocationDegrees
    Annotation.coordinate.longitude = userLng as! CLLocationDegrees
}

If you are certainly sure it shouldn't be nil at that point (viewDidLoad:), you might have to provide us more code so we can help you to determine where went wrong.

Remember, always make sure it's not nil before you unwrap it, if not, don't use !.

Upvotes: 2

Related Questions