Checking for parameters for CLLocationCoordinate2DMake - ios

I have a mapview where I want to check if latitude og longitude values are empty/nil or not, but either the app crashes, or Xcode is complaining about optional types and what not.
This is my current code, but I want to find out what the best way to get correct format for latitude and longitude coordinates:
if let latitude = detailItem!["lat"] as? Double {
if let longitude = detailItem!["lon"] as? Double {
// Get location
let location = CLLocationCoordinate2DMake(latitude, longitude)
// Set region
let region = MKCoordinateRegionMakeWithDistance(location, 2000, 2000)
mapCell.mapView.setRegion(region, animated: false)
// Add pin to map
let marker = MKPointAnnotation()
marker.coordinate = location
marker.title = String(detailItem!["name"]!)
mapCell.mapView.addAnnotation(marker)
}
}
This crashes entries with values.

Related

How do you get a label to be read as a number?

My map annotation works well when physically putting the numbers in, but, how do I use it so,
for example, latitudelabel.text is read as the latitude rather than 38.897957?
Here is the code:
func showEmergenyOnMap() {
let emergency = MKPointAnnotation()
emergency.title = "Ongoing Emergency"
emergency.coordinate = CLLocationCoordinate2D(latitude: 38.897957, longitude: -77.036560)
Map.addAnnotation(emergency)
}
Covert string to double.
let lati = Double(label.text)
// do same for longi
Then init coordinate
let coords = CLLocationCoordinate2D(latitude: lati, longitude: longi)
UILabel's text property is an Optional variable so it can have a value or a nil. First of all you need to safely unwrap that value because CLLocationDegrees initializer takes a non-optional String. You can see the below example on how to convert labels text to CLLocationCoordinate2D,
var latitude: CLLocationDegrees = 0.0
var longitude: CLLocationDegrees = 0.0
if let latText = latitudelabel.text, let lat = CLLocationDegrees(latText) {
latitude = lat
}
if let longText = longitudelabel.text, let long = CLLocationDegrees(longText) {
longitude = long
}
let location = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)

Annotation.coordinate does not match coordinate.latitude and coordinate.longitude

In my project I use LocationSearchTable / MKLocalSearch. When a user clicks on an item, my add annotation method is called in MapViewController:
func dropPinZoomIn(placemark: MKPlacemark) {
// cache the pin
selectedPin = placemark
// create the pin
let annotation = MKPointAnnotation()
annotation.coordinate = placemark.coordinate
annotation.title = placemark.name
if let streetNumber = placemark.subThoroughfare,
let city = placemark.locality,
let state = placemark.administrativeArea {
annotation.subtitle = "\(streetNumber) \(city) \(state)"
}
// add the pin the the mapView
mapView.addAnnotation(annotation)
let span = MKCoordinateSpanMake(0.01, 0.01)
let region = MKCoordinateRegionMake(annotation.coordinate, span)
mapView.setRegion(region, animated: true)
print(placemark.coordinate)
print(placemark.coordinate.latitude)
print(placemark.coordinate.longitude)
At the end, when I print the coordinate, I get a longer version whereas when I print the latitude and longitude separately, it rounds off the number near the end. This is causing me troubles later when I need to compare coordinates. How can I prevent this rounding? As an example, here are my results:
CLLocationCoordinate2D(latitude: 37.331413259110334, longitude: -122.03048408031462)
CLLocationCoordinate2D(latitude: 37.3314132591103, . . longitude: -122.030484080315)
Try the following code to prevent rounds off the number.
print(coordinate)
print(coordinate.latitude.debugDescription)
print(coordinate.longitude.debugDescription)
Result:
CLLocationCoordinate2D(latitude: -33.499989999999997, longitude: 150.255)
-33.499989999999997
150.255
Note:
The type of coordinate.latitude/coordinate.longitude is CLLocationDegrees. This type is alias for Double. Comparing Double or Float values with == will not give the expected result in most programming languages, which means that numbers that you think should be equal are in fact slightly different. Instead compute the absolute difference and handle the numbers as equal if the difference is below some threshold. See Compare double to zero using epsilon for more explanations.

How to extract lat/long placemark.coordinate in Swift?

I added a location search bar to my app. The tableview controller consists of the user location lat/long as well as the destination (address the user inputs into the search bar). As far as I can tell the latitude / longitude is within the placemark.coordinate:
placemark.coordinate = CLLocationCoordinate2D(latitude: 45.253519203737767, longitude: -66.070974382763978)
I have two variables: destLat and destLong. How I can extract the latitude and longitude from placemark.coordinate and place into the two variables mentioned above?
related code:
// cache the pin
selectedPin = placemark
// clear existing pins
mapView.removeAnnotations(mapView.annotations)
let annotation = MKPointAnnotation()
annotation.coordinate = placemark.coordinate
annotation.title = placemark.name
if let city = placemark.locality,
let prov = placemark.administrativeArea {
annotation.subtitle = "\(city), \(prov)"
}
let destination = placemark.coordinate
print("Destination coordinates: \(destination)")
let name = placemark.name
print("Placemark Name: \(name!)")
mapView.addAnnotation(annotation)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegionMake(placemark.coordinate, span)
mapView.setRegion(region, animated: true)
Console output:
Perhaps your were thinking too hard. You can assign values to these variables just like any other:
let (destLat, destLong) = (placemark.coordinate.latitude, placemark.coordinate.longitude)
If both variable you have declare is type of Double then you need to simply need to access the latitude and longitude property of CLLocationCoordinate2D.
destLat = destination.latitude
destLong = destination.longitude
If type of both var is different then simply change it to Double works for you.

Convert String from CoreData into CLLocationDegrees/ CLLocationCoordinate2D

I had been struggling to store CLLocationCoordinate2D data from markers on a google maps to CoreData. This cannot be done directly but I found a work around where I take the coordinates, split into CLLocationDegrees, convert it into a string text and store it. I do this by the following:
let marker = GMSMarker()
marker.position = CLLocationCoordinate2DMake(place.coordinate.latitude, place.coordinate.longitude)
let newPlaceLatitude = place.coordinate.latitude
print(newPlaceLatitude)
var latitudeText:String = "\(newPlaceLatitude)"
self.latitudeText = "\(newPlaceLatitude)"
let newPlaceLongitude = place.coordinate.longitude
print(newPlaceLongitude)
var longitudeText:String = "\(newPlaceLongitude)"
self.longitudeText = "\(newPlaceLongitude)"
Storing into CoreData:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let newPlace = NSEntityDescription.insertNewObject(forEntityName:
"StoredPlace", into: context)
newPlace.setValue(latitudeText, forKeyPath: "latitude")
newPlace.setValue(longitudeText, forKeyPath: "longitude")
However now I am struggling to reconstruct the strings back into CLLocationCoordinates. How would I turn a string to a CLLocationDegree/CLLocationCoordinate2D ? This is supposedly pretty simple but I have found that the following method doesn't work:
let latitude: CLLocationDegrees = Double(latitudeText)!
let longitude: CLLocationDegrees = Double(longitudeText)!
let markers = GMSMarker()
print(latitude)
print(longitude)
markers.position = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
any other suggestions about how to change string to coordinate?
CLLocation's latitude and longitude are doubles, so with that in mind, you might consider having latitude and longitude properties that are doubles on your StoredPlace object. I called the properties coordinateX and coordinateY so it's easier to remember that they're custom coordinates, not "factory" properties.
You could create an extension in a file called StoredPlace+Extension.swift that looks like this:
import CoreData
import CoreLocation
extension StoredPlace {
func location() -> CLLocation {
let location = CLLocation(latitude: self.coordinateX, longitude: self.coordinateY)
return location
}
}
With this extension, you can then get the coordinates out of your results as follows:
for result in results {
print("coordinate = \(result.location().coordinate)")
print("latitude = \(result.location().coordinate.latitude)")
print("longitude = \(result.location().coordinate.longitude)")
}
You need to typecast your lat and long in decimal values, more preferable is double instead of float because of precision value which can drop pins at perfect locations.
Type casting in double using as keyword:
(yourCordinateString as NSString).doubleValue
casting in float values:
(yourCordinateString as NSString).floatValue

Swift loop through array

I'm trying to loop through an array with coordinates and show markers on a map with this code:
for index in 0...3 {
let latitude: Double = latCoordinate.objectAtIndex(index) as! Double
let longitude: Double = longCoordinate.objectAtIndex(index) as! Double
let position = CLLocationCoordinate2DMake(latitude, longitude)
print([latitude],[longitude])
let marker = GMSMarker(position: position)
marker.title = "Hello World"
marker.map = self.mapView
}
But I just get one marker on the map, it should be 4. Why can't I see the other markers on the map?
Your code looks good for displaying the marker, but are you sure the coordinates are correct? - Just looked at the comments again and the issue is in how you're populating your array, if you only have one coordinate in your array then you're only going to see one marker on the map.
This code from my app adds all the coordinates to a GMSCoordinateBounds and then sets the GMSMapView camera to the bounds of all the coordinates - so everything should be visible on the displayed map.
func plotAll(){
let bounds = GMSCoordinateBounds.init()
for property in fetchedResultsController.fetchedObjects!
{
let capitalAsset : CapitalAsset = property as! CapitalAsset
let marker = GMSMarker.init()
marker.draggable = false
marker.snippet = capitalAsset.address
let location = CLLocationCoordinate2DMake(Double(capitalAsset.latitude!), Double(capitalAsset.longitude!))
marker.position = location
marker.map = mapView
// Update bounds to include marker
bounds.includingCoordinate(marker.position)
}
let camera = mapView.cameraForBounds(bounds, insets:UIEdgeInsetsZero)
mapView.camera = camera;
}
Hope that helps.

Resources