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

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.
}
}

Related

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?

Trying to run a PFQuery that will lead to only one result being returned however the parameters that I am envoking are not specific enough

I am trying to run a PFQuery in order to find specific results for an address stored in the server. However, when I try for a specific address I am always returned 0. The fields that this class possesses are objectId, startTime and title. I am unsure if this is the best way to pose the question but is there a type of general format that would allow me to query for the latest address stored and return that as a string in the code? Here is what I have written thus far in my load screen view controller, which is designed to place a user based on her/his location.
import UIKit
import CoreLocation
import Parse
class LoadViewController: UIViewController, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
var lastUserLocation = "nil"
var address = ""
var startTime = ""
func findEventProximity(eventObjectId: String){
var eventObjectIdQuery = PFQuery(className: "Events")
eventObjectIdQuery.orderByDescending("createdAt")
eventObjectIdQuery.whereKey("objectId", equalTo: eventObjectId)
eventObjectIdQuery.findObjectsInBackgroundWithBlock({ (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
print(objects!.count)
if let objects = objects as [PFObject]? {
for object in objects {
object["objectId"] = selectedEventObjectId
/* need to decide wether to store Time in createNewEvent as NSDate or just string
if object["date"] != nil {
self.eventDateLabel.text = object["date"] as! NSDate
}
*/
print("\(object["address"] as! String)")
}
} else {
print(error)
}
}
})
}
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
findEventProximity(selectedEventObjectId)
// Do any additional setup after loading the view.
}
/*MARK: LOCATION*/
/*MARK: LOCATION*/
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
self.locationManager.stopUpdatingLocation()
let userLocation: CLLocation = locations[0]
let userLocationLat = locations[0].coordinate.latitude
let userLocationLong = locations[0].coordinate.longitude
var location = CLLocation(latitude: userLocationLat, longitude: userLocationLong)
print("\(userLocationLat), \(userLocationLong)")
let locationsToCheck: [CLLocation] = [
CLLocation(latitude: lat, long),
CLLocation(latitude: lat, long),
CLLocation(latitude: lat, long),
CLLocation(latitude: lat, long)
]
let locationTags: [String] = [
"P1",
"P2",
"P3",
"P4"
]
var closestInMeters: Double = 50000.0
var closestIndex: Int = -1
for (locationIndex, potentialLocation) in locationsToCheck.enumerate() {
let proximityToLocationInMeters: Double = userLocation.distanceFromLocation(potentialLocation)
if proximityToLocationInMeters < closestInMeters {
closestInMeters = proximityToLocationInMeters
closestIndex = locationIndex
}
}
if (closestIndex == -1) {
self.lastUserLocation = "Other"
// SCLAlertView().showError("No Filter Range", subTitle: "Sorry! We haven’t got a Filter Range for you yet, email us and we’ll get right on it.").setDismissBlock({ () -> Void in
// selectedLocation = self.locationObjectIdArray[0]
// self.performSegueWithIdentifier("eventTableSegue", sender: self)
// })
// self.activityIndicator.stopAnimating()
// UIApplication.sharedApplication().endIgnoringInteractionEvents()
} else if locationTags[closestIndex] != self.lastUserLocation {
self.lastUserLocation = locationTags[closestIndex]
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}

Save to parse manually after data has been queried

I am using Parse pinInBackground feature to pin data (image, text, date, coordinates) in the background and that data is queried every time the app is opened.The app is used to log a photo and the location and coordinates.So every entry you make is queried and displays in a tableview (only the count of entries yet).
I want to be able to let the user manually sink with Parse.com and not use the saveEventually feature.
Meaning I want a button and when pressed the queried data must sink with Parse and the be in pinned.
Here is how my data is pinned
#IBAction func submitButton(sender: AnyObject) {
locationLogs["title"] = log.title
locationLogs["description"] = log.descriptionOf
println("log = \(log.title)")
println("log = \(log.descriptionOf)")
locationLogs.pinInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
if (success) {
}else{
println("error = \(error)")
}}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
let location:CLLocationCoordinate2D = manager.location.coordinate
let altitude: CLLocationDistance = manager.location.altitude
println("new long= \(location.longitude)")
println("new lat= \(location.latitude)")
println("new altitude= \(altitude)")
println("new timestamp = \(timestamp)")
locationLogs["longitude"] = location.longitude
locationLogs["latitude"] = location.latitude
locationLogs["altitude"] = altitude
locationLogs["timestamp"] = timestamp
}
And here I query it
var result : AnyObject?
override func viewDidLoad() {
super.viewDidLoad()
let query = PFQuery(className:"LocationLogs")
query.fromLocalDatastore()
query.findObjectsInBackgroundWithBlock( { (NSArray results, NSError error) in
if error == nil && results != nil {
self.result = results
println("count = \(self.result!.count)")
self.loggedItemsTableView.reloadData()
}else{
println("ERRRROOOORRRR HORROOORRR= \(error)")
}
})
}
I have tried to use this command:
result?.saveAllInBackground()
But this only gave back an error.
Can someone please give me the correct code on how to do this or give me a link showing me how.
Here is a full code explanation on how I solved it:
//create an Array
var tableData: NSArray = []
func queryAll() {
let query = PFQuery(className:"LocationLogs")
query.fromLocalDatastore()
query.findObjectsInBackgroundWithBlock( { (NSArray results, NSError error) in
if error == nil && results != nil {
println("array = \(results)" )
self.tableData = results!
self.loggedItemsTableView.reloadData()
}else{
println("ERRRROOOORRRR HORROOORRR= \(error)")
}
})
}
//Call save on the class and not the object
PFObject.saveAllInBackground(self.tableData as [AnyObject], block: { (success: Bool, error: NSError?) -> Void in
if (success) {
//Remember to unpin the data if it will no longer be needed
PFObject.unpinAllInBackground(self.tableData as [AnyObject])
println("Pinned Data has successfully been saved")
}else{
println("error= \(error?.localizedDescription)")
}
})
Use this to safely cast/checked your object
if let results = self.result { // this will verify if your self.result is a non-nil array of object
// if it has a value then it will be passed to results
// you can now safely proceed on saving your objects
PFObject.saveAllInBackground(results, block: { (succeeded, error) -> Void in
// additional code
if succeeded {
// alert, remove hud ......
}else{
if let reqError = error {
println(reqError.localizedDescription)
}
}
})
}
struct log {
// this is dummy datastructure that imitate some part of your code ... you dont need it
var title = ""
var descriptionOf = ""
}
struct LocationInfo{
var title:String!
var description:String!
var location:PFGeoPoint!
var timestamp:NSDate!
var username:String
}
var locationManager = CLLocationManager()
var arrayOfLocations = [LocationInfo]()
func submitButton(sender: AnyObject) {
var logData = log()
var point = OneLocation(locationManager)
let username = PFUser.currentUser()?.username
var locationLogs = PFObject(className: "")
locationLogs["title"] = logData.title
locationLogs["description"] = logData.descriptionOf
locationLogs["Location"] = point
locationLogs["username"] = username
locationLogs["TimeStamp"] = locationManager.location.timestamp
locationLogs.saveInBackgroundWithBlock { (success:Bool, error:NSError?) -> Void in
if error == nil
{
println("data was save")
}
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
CLGeocoder().reverseGeocodeLocation (manager.location, completionHandler: {(placemarks, error)->Void in
var UserCurrentLocation:CLLocationCoordinate2D = manager.location.coordinate
// println("User's parking Location : \(UserCurrentLocation.latitude) \(UserCurrentLocation.longitude)")
if (error != nil) {
println("Error")
return
}
locationManager.stopUpdatingLocation()
})
}
func OneLocation(Manager:CLLocationManager)->PFGeoPoint{
var latitude = Manager.location.coordinate.latitude
var longitude = Manager.location.coordinate.longitude
var point = PFGeoPoint(latitude: latitude, longitude: longitude)
return point
}
func QueryFromParse(){
var query = PFQuery(className: "")
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil
{
if let new_objects = objects as? [PFObject]
{
for SingleObject in new_objects
{
// with this single object you could get the description, title , username,etc
var location = SingleObject["Location"] as! PFGeoPoint
var username = SingleObject["username"] as! String
var title = SingleObject["title"] as! String
var time = SingleObject["TimeStamp"] as! NSDate
var description = SingleObject["description"] as! String
var singleLocationInfo = LocationInfo(title: title, description: description, location: location, timestamp: time, username: username)
arrayOfLocations.append(singleLocationInfo)
// reload data for the tableview
}
}
}
else
{
println("error")
}
}
}
Therefore you have an arrayoflocations that can be used to populate data in your tableView
Struct log is a dummy datastructure
And also I don't know if that was what you wanted ... but you should get the idea..
Hope that helps..

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

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()

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