0

I'm trying to get my map to show directions to a local searched location from the current user location.

I'm getting an EXC_BAD_INSTRUCTION on the line:

let region = MKCoordinateRegionMakeWithDistance(userLocation.location.coordinate, 2000, 2000)`

And on the line:

else {
    self.showRoute(response)
}

I have a feeling the nil it's receiving is from the user location, which I'm not sure why it would be receiving a nil there.

Here is the full code for my view controller if needed:

class RouteViewController: UIViewController, MKMapViewDelegate {

@IBOutlet weak var routeMap: MKMapView!

var destination = MKMapItem?()

override func viewDidLoad() {
    super.viewDidLoad()

    routeMap.showsUserLocation = true
    routeMap.delegate = self
    self.getDirections()
}

func getDirections() {

    let request = MKDirectionsRequest()
    request.setSource(MKMapItem.mapItemForCurrentLocation())
    request.setDestination(destination!)
    request.requestsAlternateRoutes = false

    let directions = MKDirections(request: request)

    directions.calculateDirectionsWithCompletionHandler({(response:
        MKDirectionsResponse!, error: NSError!) in

        if error != nil {
            println("Error getting directions")
        } else {
            self.showRoute(response)
        }

    })
}

func showRoute(response: MKDirectionsResponse) {

    for route in response.routes as! [MKRoute] {

        routeMap.addOverlay(route.polyline,
            level: MKOverlayLevel.AboveRoads)

        for step in route.steps {
            println(step.instructions)
        }
    }
    let userLocation = routeMap.userLocation
    let region = MKCoordinateRegionMakeWithDistance(
        userLocation.location.coordinate, 2000, 2000)

    routeMap.setRegion(region, animated: true)
}

func mapView(mapView: MKMapView!, rendererForOverlay
    overlay: MKOverlay!) -> MKOverlayRenderer! {
        let renderer = MKPolylineRenderer(overlay: overlay)

        renderer.strokeColor = UIColor.blueColor()
        renderer.lineWidth = 5.0
        return renderer
}


}

And the segue code:

override func prepareForSegue(segue: UIStoryboardSegue,
    sender: AnyObject?) {
        let routeViewController = segue.destinationViewController
            as! RouteViewController

        let indexPath = self.tableView.indexPathForSelectedRow()

        let row = indexPath?.row

        routeViewController.destination = mapItems[row!]
}

Any help would be appreciated, thanks!

luk2302
  • 46,204
  • 19
  • 86
  • 119
Alec
  • 213
  • 1
  • 4
  • 13
  • You need to check that the user's location is valid before using it. It may be nil because the location hasn't been determined or the user has denied location permission or turned off location services. Also, I am not sure about Apple's definition of `MKDirectionsHandler` - it says that it has `MKDirectionsResponse!` but that this could be nil, so I would have thought it should be `MKDirectionsResponse?` - either way you need to check for a possible nil – Paulw11 May 09 '15 at 22:22
  • @Paulw11 Sorry for the silly question, but how could I check that the location is valid? I'm using the same code for all my other user locations, so I'm not sure why it wouldn't work in this case. The first time I ran it after implementing the code, the directions worked just fine. Then I closed the build, and re-built it and then it stopped working from then on. – Alec May 09 '15 at 22:47
  • By valid, I mean not nil. You should always program defensively and check where things could be nil. Have you stepped through with the debugger to confirm that it is/isn't nil? Are you running in the simulator? Have you simulated a location? – Paulw11 May 09 '15 at 22:50
  • possible duplicate of [Fatal error: unexpectedly found nil while unwrapping an Optional values](http://stackoverflow.com/questions/24643522/fatal-error-unexpectedly-found-nil-while-unwrapping-an-optional-values) – GoZoner May 10 '15 at 01:20

1 Answers1

0

The problem is this line:

let userLocation = routeMap.userLocation

The result, userLocation might be nil, and its location might be nil, because the map might not have been told to, or succeeded in acquiring, the user's location. You are not taking into account that possibility.

The way to do that is to unwrap the Optionals safely and proceed only if the unwrapping succeeded:

if let userLocation = routeMap.userLocation, loc = userLocation.location {
    let region = MKCoordinateRegionMakeWithDistance(
        loc.coordinate, 2000, 2000)
    routeMap.setRegion(region, animated: true)
}

We don't need the userLocation separately for anything, so we can collapse that into a single test:

if let loc = routeMap.userLocation.location {
    let region = MKCoordinateRegionMakeWithDistance(
        loc.coordinate, 2000, 2000)
    routeMap.setRegion(region, animated: true)
}
matt
  • 447,615
  • 74
  • 748
  • 977
  • That didn't do anything, still getting the same error on the same line of code. – Alec May 09 '15 at 23:04
  • That was more work than I was expecting! :) Fixed now. Sorry about that. – matt May 09 '15 at 23:14
  • Well it got rid of the error, but now the `setRegion` isn't working. It loads the MapView, and then doesn't zoom in. – Alec May 10 '15 at 04:39
  • Of course not. You have no user location. So your region code never runs. We already knew that! But that would be a different question. You were crashing on nil. We solved it. The end. If you have a new question, ask a new question. – matt May 10 '15 at 04:43