how to retrive location from a PFGeopoint - (Parse.com and Swift) and show it on the map with Xcode 6.2 - ios

There are some answer on this, but related to different problems and all in objective-c.
I save in a parse class "Position" positions of users with this:
var locationManager = CLLocationManager()
var lat = locationManager.location.coordinate.latitude
var lon = locationManager.location.coordinate.longitude
let myGeoPoint = PFGeoPoint(latitude: lat, longitude:lon)
let myParseId = PFUser.currentUser().objectId //PFUser.currentUser().objectId
println("****** this is my geoPoint: \(myGeoPoint)")
func sendPosition(userOfPosition: User) {
let takePosition = PFObject(className: "Position")
takePosition.setObject(myParseId, forKey: "who") //who
takePosition.setObject(myGeoPoint, forKey: "where")
takePosition.saveInBackgroundWithBlock(nil)
}
sendPosition(currentUser()!)
so this is my result:
then I want to show them on map, but how? don't understand how to retrive latitude and longitude from "where" column the code below doesn't work:
import UIKit
import MapKit
class MapViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
var locationManager : CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
var locationManager = CLLocationManager()
var lat = locationManager.location.coordinate.latitude
var lon = locationManager.location.coordinate.longitude
let location = CLLocationCoordinate2D(latitude: lat, longitude: lon)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegionMake(location, span)
mapView.setRegion(region, animated: true)
let anotation = MKPointAnnotation()
anotation.setCoordinate(location)
anotation.title = "my title"
anotation.subtitle = " my subtitle"
mapView.addAnnotation(anotation)
println("****** Welcome in MapViewController")
//MARK: (471) Crossing Positions
//*******************************************************
let myGeoPoint = PFGeoPoint(latitude: lat, longitude:lon)
let myParseId = PFUser.currentUser().objectId //PFUser.currentUser().objectId
println("****** this is my geoPoint from map view controller: \(myGeoPoint)")
//
// var inspector = PFQuery(className:"GameScore")
// inspector.saveInBackgroundWithBlock {
// (success: Bool, error: NSError?) -> Void in
// if (success) {
// // The object has been saved.
// var the = inspector.objectId
// } else {
// // There was a problem, check error.description
// }
// }
//
//
//
func filterByProximity() {
PFQuery(className: "Position")
.whereKey("where", nearGeoPoint: myGeoPoint, withinKilometers: 500.0) //(474)
.findObjectsInBackgroundWithBlock ({
objects, error in
if let proximityArray = objects as? [PFObject] {
println("****** here the proximity matches: \(proximityArray)")
for near in proximityArray {
println("here they are \(near)")
if let position = near["where"] as! PFGeoPoint {
let theirLat = position.latituide
let theirLon = position.longitude
}
let theirLat = near["where"].latitude as Double
let theirlong = near["where"].longitude as Double
let location = CLLocationCoordinate2DMake(theirLat, theirlong)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegionMake(location, span)
self.mapView.setRegion(region, animated: true)
let theirAnotation = MKPointAnnotation()
theirAnotation.setCoordinate(location)
self.mapView.addAnnotation(anotation)
}
}
})
}
filterByProximity()
// //update my position
//
// func exists() {
// PFQuery(className:"Position")
// .whereKey("who", containsString: myParseId)
// .findObjectsInBackgroundWithBlock({
// thisObject, error in
// if let result = thisObject as? [PFObject] {
// println("here the result: \(result)")
//
// let gotTheId = result[0].objectId
// println("ecco l'id singolo \(gotTheId)")
//
// //******** update function ********
// var query = PFQuery(className:"Position")
// query.getObjectInBackgroundWithId(gotTheId) {
// (usingObject: PFObject?, error: NSError?) -> Void in
// if error != nil {
// println(error)
// } else if let objectToupdate = usingObject {
// println("else occurred")
// objectToupdate["where"] = myGeoPoint
// println("position should be updated")
// objectToupdate.saveInBackgroundWithBlock(nil)
// println("position should be saved")
//
// }
// }
// //******** end update function ********
// }
// })
// }
//
// exists()
//*******************************************************
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Update after first answers
tried to check for optionals, but have this message:
after not down casting the double:

the 'where' is a PFGeoPoint, you can just call latitude and longitude on them
Try something like this - I'm not 100% sure in Swift syntax, yet
if(geoPoint)
{
if(geoPoint!.latitude)
{
let latitude = geoPoint!.latitude as double;
}
}

this worked. Was both a matter of optionals, and a matter of variables, I was using the wrong ones:
//MARK: (471) Crossing Positions
//*******************************************************
let myGeoPoint = PFGeoPoint(latitude: lat, longitude:lon)
let myParseId = PFUser.currentUser().objectId //PFUser.currentUser().objectId
var radius = 100.0
println("****** this is my geoPoint from map view controller: \(myGeoPoint)")
//MARK: *** let's look for other users ***
var nearArray : [CLLocationCoordinate2D] = []
func filterByProximity() {
PFQuery(className: "Position")
.whereKey("where", nearGeoPoint: myGeoPoint, withinKilometers: radius) //(474)
.findObjectsInBackgroundWithBlock ({
objects, error in
if let proximityArray = objects as? [PFObject] {
// println("****** here the proximity matches: \(proximityArray)")
for near in proximityArray {
// println("here they are \(near)")
let position = near["where"] as? PFGeoPoint
var theirLat = position?.latitude //this is an optional
var theirLong = position?.longitude //this is an optional
var theirLocation = CLLocationCoordinate2D(latitude: theirLat!, longitude: theirLong!)
nearArray.append(theirLocation)
if nearArray.isEmpty {
println("*** ERROR! anyone close by ***")
} else
{
for person in nearArray {
let span = MKCoordinateSpanMake(2.50, 2.50)
let region = MKCoordinateRegionMake(theirLocation, span)
self.mapView.setRegion(region, animated: true)
let theirAnotation = MKPointAnnotation()
theirAnotation.setCoordinate(theirLocation)
theirAnotation.title = near["who"] as String
self.mapView.addAnnotation(theirAnotation)
}
}
}
println("****** in a radius of \(radius) there are \(nearArray.count) bikers ******")
}
})
}
filterByProximity()

Related

Google map showing skin color screen

Viewdidload method
override func viewDidLoad() {
super.viewDidLoad()
selectedAdressType = "pickup"
mapV.delegate = self
styleOfMap()
mapV.settings.myLocationButton = true
mapV.isMyLocationEnabled = true
// self.pickupAddressTxtF.setLeftPaddingPoints(7)
//self.destinationAddressTxtF.setLeftPaddingPoints(7)
googleLocationTableV.rowHeight = UITableViewAutomaticDimension
googleLocationTableV.estimatedRowHeight = 50
googleLocationTableV.tableFooterView = UIView(frame: .zero)
savedLocationTableV.keyboardDismissMode = .interactive
googleLocationTableV.keyboardDismissMode = .interactive
// Add footer for set pinn location
googleLocationTableV.tableFooterView = AddFooterView()
savedLocationTableV.tableFooterView = AddFooterView()
redirectMap(to: Double("\(latitude)") ?? 0.0, lng: Double("\(longitude)") ?? 0.0)
let userDefaults = UserDefaults.standard
if userDefaults.object(forKey: "LocationInitialData") != nil {
let retriveArrayData = UserDefaults.standard.object(forKey: "LocationInitialData") as? NSData
let dataDic = (NSKeyedUnarchiver.unarchiveObject(with: retriveArrayData! as Data) as? NSDictionary)
print(" saved response = \(dataDic!)")
self.recentSerchList = dataDic?.value(forKey: "recent_search")as! NSArray
self.savedLocationList = dataDic?.value(forKey: "save_address")as! NSArray
self.savedLocationTableV.reloadData()
}
savedLocationTableV.keyboardDismissMode = .onDrag
googleLocationTableV.keyboardDismissMode = .onDrag
// addressSerachApiCall()
if Language.isRTL {
pickupAddressTxtF.textAlignment = .right
}
}
Redirect Method
func redirectMap(to lat: Double, lng: Double) {
// [_mapView clear];
let position: CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat, lng)
let camera = GMSCameraPosition(target: position, zoom: 16, bearing: 0, viewingAngle: 0)
mapV.animate(to: camera)
}
Styling of map show "Unable to find style.json"
func styleOfMap() {
do {
if let styleURL = Bundle.main.url(forResource: "style", withExtension: "json") {
mapV.mapStyle = try GMSMapStyle(contentsOfFileURL: styleURL)
} else {
NSLog("Unable to find style.json")
}
} catch {
NSLog("One or more of the map styles failed to load. \(error)")
}
}

MKAnnotation doesn't appear

I'm writing flight ticket's app and have some troubles with map annotation's
So we have view, that showing all ticket information, and map with departure city and destination
Here's view loading :
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
}
override func viewWillAppear(_ animated: Bool) {
configureView(showingReturnData: showingReturnData, fromTicket: showingTicketNow)
designSetup()
mapSetting()
}
Converting to coordinates :
func gettingCoordinates(cityString: String) -> CLLocationCoordinate2D {
let geocoder = CLGeocoder()
var returningCoordinate = CLLocationCoordinate2D()
geocoder.geocodeAddressString(cityString) { (placemarksArray, error) in
if error == nil && placemarksArray?.count != 0 {
let placemark = placemarksArray![0]
print(placemark.country, placemark.name,
placemark.location!.coordinate.longitude,
placemark.location!.coordinate.latitude)
//Here output:
Optional("Japan") Optional("Tokyo") 139.6917 35.689506
Optional("Russia") Optional("Moscow") 37.60946 55.7615902
returningCoordinate.longitude = placemark.location!.coordinate.longitude
returningCoordinate.latitude = placemark.location!.coordinate.latitude
} else {
print(error!)
}
}
return returningCoordinate
}
And then adding annotations to map, but It's always the same place, near Africa in ocean
func mapSetting() {
let fromPlacemark = gettingCoordinates(cityString: showingTicketNow.fromCityName)
let toPlacemark = gettingCoordinates(cityString: showingTicketNow.toCityName)
let fromAnnotation = MKPointAnnotation()
fromAnnotation.title = fromCityName.text!
fromAnnotation.coordinate = fromPlacemark
mapView.addAnnotation(fromAnnotation)
let toAnnotation = MKPointAnnotation()
toAnnotation.title = toCityName.text!
toAnnotation.coordinate = toPlacemark
mapView.addAnnotation(toAnnotation)
let coordinateRegion = MKCoordinateRegion(center: toPlacemark, latitudinalMeters:
10000, longitudinalMeters: 10000)
mapView.setRegion(coordinateRegion, animated: true)
}
What i'm doing wrong?

I get an empty CLLocationCoordinates array when loading data from user defaults

I'm trying to store to UserDefaults an array of CCLocationCoordinates from the tracking portion of my app paired with the name of the tracked route as key, to be able to recall it later on to use it within a function.
The problem is that when I call that function I get the index out of range error. I checked and the array is empty.
As I'm new to user defaults I tried to see other similar posts but they're all about NSUserDefaults and didn't find a solution.
Heres the code for the functions for storing and recalling the array:
func stopTracking2() {
self.trackingIsActive = false
self.trackigButton.backgroundColor = UIColor.yellow
locationManager.stopUpdatingLocation()
let stopRoutePosition = RouteAnnotation(title: "Route Stop", coordinate: (locationManager.location?.coordinate)!, imageName: "Route Stop")
self.actualRouteInUseAnnotations.append(stopRoutePosition)
print(actualRouteInUseCoordinatesArray)
print(actualRouteInUseAnnotations)
drawRoutePolyline() // draw line to show route
// checkAlerts2() // check if there is any notified problem on our route and marks it with a blue circle, now called at programmed checking
saveRouteToUserDefaults()
postRouteToAnalitics() // store route anonymously to FIrebase
}
func saveRouteToUserDefaults() {
// save actualRouteInUseCoordinatesArray : change for function
// userDefaults.set(actualRouteInUseCoordinatesArray, forKey: "\(String(describing: userRoute))")
storeCoordinates(actualRouteInUseCoordinatesArray)
}
// Store an array of CLLocationCoordinate2D
func storeCoordinates(_ coordinates: [CLLocationCoordinate2D]) {
let locations = coordinates.map { coordinate -> CLLocation in
return CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
}
let archived = NSKeyedArchiver.archivedData(withRootObject: locations)
userDefaults.set(archived, forKey: "\(String(describing: userRoute))")
userDefaults.synchronize()
}
func loadRouteFromUserDefaults() {
// gets entry from userRouteArray stored in userDefaults and append them into actualRouteInUseCoordinatesArray
actualRouteInUseCoordinatesArray.removeAll()
actualRouteInUseCoordinatesArray = userDefaults.object(forKey: "\(String(describing: userRoute))") as? [CLLocationCoordinate2D] ?? [CLLocationCoordinate2D]() // here we get the right set of coordinates for the route we are about to do the check on
// load route coordinates from UserDefaults
// actualRouteInUseCoordinatesArray = loadCoordinates()! //error found nil
}
// Return an array of CLLocationCoordinate2D
func loadCoordinates() -> [CLLocationCoordinate2D]? {
guard let archived = userDefaults.object(forKey: "\(String(describing: userRoute))") as? Data,
let locations = NSKeyedUnarchiver.unarchiveObject(with: archived) as? [CLLocation] else {
return nil
}
let coordinates = locations.map { location -> CLLocationCoordinate2D in
return location.coordinate
}
return coordinates
}
}
extension NewMapViewController {
// ALERTS :
func checkAlerts2() {
loadRouteFromUserDefaults() //load route coordinates to check in
// CHECK IF ANY OBSTACLE IS OUN OUR ROUTE BY COMPARING DISTANCES
while trackingCoordinatesArrayPosition != ( (actualRouteInUseCoordinatesArray.count) - 1) {
print("checking is started")
print(actualRouteInUseCoordinatesArray)
let trackingLatitude = actualRouteInUseCoordinatesArray[trackingCoordinatesArrayPosition].latitude
let trackingLongitude = actualRouteInUseCoordinatesArray[trackingCoordinatesArrayPosition].longitude
let alertLatitude = alertNotificationCoordinatesArray[alertNotificationCoordinatesArrayPosition].latitude
let alertLongitude = alertNotificationCoordinatesArray[alertNotificationCoordinatesArrayPosition].longitude
let coordinateFrom = CLLocation(latitude: trackingLatitude, longitude: trackingLongitude)
let coordinateTo = CLLocation(latitude: alertLatitude, longitude: alertLongitude)
let coordinatesDistanceInMeters = coordinateFrom.distance(from: coordinateTo)
// CHECK SENSITIVITY: sets the distance in meters for an alert to be considered an obstacle
if coordinatesDistanceInMeters <= 10 {
print( "found problem")
routeObstacle.append(alertNotificationCoordinatesArray[alertNotificationCoordinatesArrayPosition]) // populate obstacles array
trackingCoordinatesArrayPosition = ( trackingCoordinatesArrayPosition + 1)
}
else if alertNotificationCoordinatesArrayPosition < ((alertNotificationCoordinatesArray.count) - 1) {
alertNotificationCoordinatesArrayPosition = alertNotificationCoordinatesArrayPosition + 1
}
else if alertNotificationCoordinatesArrayPosition == (alertNotificationCoordinatesArray.count - 1) {
trackingCoordinatesArrayPosition = ( trackingCoordinatesArrayPosition + 1)
alertNotificationCoordinatesArrayPosition = 0
}
}
findObstacles()
NewMapViewController.checkCounter = 0
displayObstacles()
}
In the extension you can see the function that uses the array.
Right after the print of the array I get the index out of range error.
Thanks as usual to the community.
After trying various solutions offered I decided to rewrite the whole thing.
So after finding a post on how to code/decode my array to string I decided it was the way to go. It shouldn't be heavy on the system as it's a string that gets saved. Please let me know what you think of this solution.
Thank to #Sh_Khan to point out it was a decoding issue, and to #Moritz to point out I was performing a bad practice.
So the code is:
func storeRoute() {
// first we code the CLLocationCoordinate2D array to string
// second we store string into userDefaults
userDefaults.set(encodeCoordinates(coords: actualRouteInUseCoordinatesArray), forKey: "\(String(describing: NewMapViewController.userRoute))")
}
func loadRoute() {
//first se load string from user defaults
let route = userDefaults.string(forKey: "\(String(describing: NewMapViewController.userRoute))")
print("loaded route is \(route!))")
//second we decode it into CLLocationCoordinate2D array
actualRouteInUseCoordinatesArray = decodeCoordinates(encodedString: route!)
print("decoded route array is \(actualRouteInUseCoordinatesArray))")
}
func encodeCoordinates(coords: [CLLocationCoordinate2D]) -> String {
let flattenedCoords: [String] = coords.map { coord -> String in "\(coord.latitude):\(coord.longitude)" }
let encodedString: String = flattenedCoords.joined(separator: ",")
return encodedString
}
func decodeCoordinates(encodedString: String) -> [CLLocationCoordinate2D] {
let flattenedCoords: [String] = encodedString.components(separatedBy: ",")
let coords: [CLLocationCoordinate2D] = flattenedCoords.map { coord -> CLLocationCoordinate2D in
let split = coord.components(separatedBy: ":")
if split.count == 2 {
let latitude: Double = Double(split[0]) ?? 0
let longitude: Double = Double(split[1]) ?? 0
return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
} else {
return CLLocationCoordinate2D()
}
}
return coords
}
Rather than using heavy-weight objectiv-c-ish NSKeyed(Un)Archiver and making a detour via CLLocation I recommend to extend CLLocationCoordinate2D to adopt Codable
extension CLLocationCoordinate2D : Codable {
public init(from decoder: Decoder) throws {
var arrayContainer = try decoder.unkeyedContainer()
if arrayContainer.count == 2 {
let lat = try arrayContainer.decode(CLLocationDegrees.self)
let lng = try arrayContainer.decode(CLLocationDegrees.self)
self.init(latitude: lat, longitude: lng)
} else {
throw DecodingError.dataCorruptedError(in: arrayContainer, debugDescription: "Coordinate array must contain two items")
}
}
public func encode(to encoder: Encoder) throws {
var arrayContainer = encoder.unkeyedContainer()
try arrayContainer.encode(contentsOf: [latitude, longitude])
}
}
and replace the methods to load and save data with
func storeCoordinates(_ coordinates: [CLLocationCoordinate2D]) throws {
let data = try JSONEncoder().encode(coordinates)
UserDefaults.standard.set(data, forKey: String(describing: userRoute))
}
func loadCoordinates() -> [CLLocationCoordinate2D] {
guard let data = UserDefaults.standard.data(forKey: String(describing: userRoute)) else { return [] }
do {
return try JSONDecoder().decode([CLLocationCoordinate2D].self, from: data)
} catch {
print(error)
return []
}
}
storeCoordinates throws it hands over a potential encoding error
Load the data with
actualRouteInUseCoordinatesArray = loadCoordinates()
and save it
do {
try storeCoordinates(actualRouteInUseCoordinatesArray)
} catch { print(error) }
Your problem is that you save it as data and try to read directly without unarchiving , You can try
let locations = [CLLocation(latitude: 123, longitude: 344),CLLocation(latitude: 123, longitude: 344),CLLocation(latitude: 123, longitude: 344)]
do {
let archived = try NSKeyedArchiver.archivedData(withRootObject: locations, requiringSecureCoding: true)
UserDefaults.standard.set(archived, forKey:"myKey")
// read savely
if let data = UserDefaults.standard.data(forKey: "myKey") {
let saved = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! [CLLocation]
print(saved)
}
}
catch {
print(error)
}

How to download my object? (issue with optionals in old Xcode version)

Since I developed this my app with Xcode 6.2, I found some problems, many solved, but this one, maybe requires to rebuild my app again.
In the code below, filterByProximity function gives an error.
I SUPPOSE is a matter of optionals (Nils Ziehn warned me here about it). Another developer told me: "download the position object using cache, and then make the query".
Well, is it possible? how can I do it? here my code:
import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
var locationManager = CLLocationManager()
var lat = locationManager.location.coordinate.latitude
var lon = locationManager.location.coordinate.longitude
let location = CLLocationCoordinate2D(latitude: lat, longitude: lon)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegionMake(location, span)
mapView.setRegion(region, animated: true)
let anotation = MKPointAnnotation()
anotation.setCoordinate(location)
anotation.title = "my title"
anotation.subtitle = " my subtitle"
mapView.addAnnotation(anotation)
println("****** Welcome in MapViewController")
//MARK: (471) Crossing Positions
//*******************************************************
let myGeoPoint = PFGeoPoint(latitude: lat, longitude:lon)
let myParseId = PFUser.currentUser().objectId //PFUser.currentUser().objectId
println("****** this is my geoPoint from map view controller: \(myGeoPoint)")
//
// var inspector = PFQuery(className:"GameScore")
// inspector.saveInBackgroundWithBlock {
// (success: Bool, error: NSError?) -> Void in
// if (success) {
// // The object has been saved.
// var the = inspector.objectId
// } else {
// // There was a problem, check error.description
// }
// }
//
//
//
//MARK: *** let's look for other users ***
// func filterByProximity() {
// PFQuery(className: "Position")
// .whereKey("where", nearGeoPoint: myGeoPoint, withinKilometers: 500.0) //(474)
// .findObjectsInBackgroundWithBlock ({
// objects, error in
// if let proximityArray = objects as? [PFObject] {
// println("****** here the proximity matches: \(proximityArray)")
// for near in proximityArray {
// println("here they are \(near)")
//
// let position = near["where"] as? PFGeoPoint
//
//// if let position = near["where"] as! PFGeoPoint {
//// let theirLat = position.latitude
//// let theirLon = position.longitude
//// }
//
// let theirLat = near["where"].latitude as Double
// let theirlong = near["where"].longitude as Double
// let location = CLLocationCoordinate2DMake(theirLat, theirlong)
// let span = MKCoordinateSpanMake(0.05, 0.05)
// let region = MKCoordinateRegionMake(location, span)
// self.mapView.setRegion(region, animated: true)
// let theirAnotation = MKPointAnnotation()
// theirAnotation.setCoordinate(location)
// self.mapView.addAnnotation(anotation)
//
//
// }
// }
// })
// }
//
// filterByProximity()
// //MARK: *** let's update my position (on Parse) ***
//
// func exists() {
// PFQuery(className:"Position")
// .whereKey("who", containsString: myParseId)
// .findObjectsInBackgroundWithBlock({
// thisObject, error in
// if let result = thisObject as? [PFObject] {
// println("here the result: \(result)")
//
// let gotTheId = result[0].objectId
// println("ecco l'id singolo \(gotTheId)")
//
// //******** update function ********
// var query = PFQuery(className:"Position")
// query.getObjectInBackgroundWithId(gotTheId) {
// (usingObject: PFObject?, error: NSError?) -> Void in
// if error != nil {
// println(error)
// } else if let objectToupdate = usingObject {
// println("else occurred")
// objectToupdate["where"] = myGeoPoint
// println("position should be updated")
// objectToupdate.saveInBackgroundWithBlock(nil)
// println("position should be saved")
//
// }
// }
// //******** end update function ********
// }
// })
// }
//
// exists()
//*******************************************************
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Swift - fatal error: unexpectedly found nil while unwrapping an Optional value on MKCoordinateRegionMakeWithDistance

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!
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)
}

Resources