Convert String from CoreData into CLLocationDegrees/ CLLocationCoordinate2D - ios

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

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)

Saving location coordinates to Core data- Swift 3

I want to save location coordinates into Core Data- what is the right way of storing these and retrieving them?
At the moment I am doing this and getting errors:
var newPlaceCoordinate = CLLocationCoordinate2D()
var newPlaceLatitude = CLLocationDegrees()
var newPlaceLongitude = CLLocationDegrees()
I get my coordinates from using Google maps API using the autocomplete widget.
let newPlaceCoordinate = place.coordinate
self.newPlaceCoordinate = place.coordinate
let newPlaceLatitude = place.coordinate.latitude
print(newPlaceLatitude)
self.newPlaceLatitude = place.coordinate.latitude
let newPlaceLongitude = place.coordinate.longitude
print(newPlaceLongitude)
self.newPlaceLongitude = place.coordinate.longitude
Then to store the coordinates I use:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let newPlace = NSEntityDescription.insertNewObject(forEntityName: "StoredPlace", into: context)
newPlace.setValue(newPlaceCoordinate, forKey: "coordinate")
newPlace.setValue(newPlaceLatitude, forKeyPath: "latitude")
newPlace.setValue(newPlaceLongitude, forKeyPath: "longitude")
And I have the attributes all set as String types.
Then to retrieve in my ViewDidLoad I have:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "StoredPlace")
request.returnsObjectsAsFaults = false
if let coordinate = result.value(forKey: "coordinate") as? String
{
let latitude = (coordinate as NSString).doubleValue
let longitude = (coordinate as NSString).doubleValue
let markers = GMSMarker()
markers.position = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
markers.icon = GMSMarker.markerImage(with: UIColor.yellow)
markers.tracksViewChanges = true
markers.map = vwGMap
}
So this is not working and producing an error of 'attribute: property = "coordinate"; desired type = NSString; given type = NSConcreteValue'. I have a few questions.
How do I save a coordinate data appropriately?
Do I save it as a CLLocationDegrees or CLLocationCoordinate2D?
How do I convert these objects into NSString or should I be using a different type in my attributes? (I tried changing it to Double or Integer but it also produced errors). I have multiple location coordinates which I would want to store and retrieve from core data.
If you are going to deal with lots of data, then CoreData is the best bet.
These are my attributes in StorePlace entity, its best to save only latitude and longitude and create coordinates from them when needed in your implementation.
#NSManaged public var newPlaceLatitude: Double
#NSManaged public var newPlaceLongitude: Double
And to insert new data, I will do
class func insert(latitude: Double, longitude: Double) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedObjectContext = appDelegate.managedObjectContext
let entity = NSEntityDescription.entity(forEntityName: "StoredPlace", in:managedObjectContext)
let newItem = StoredPlace(entity: entity!, insertInto: managedObjectContext)
newItem.newPlaceLatitude = latitude
newItem.newPlaceLongitude = longitude
do {
try managedObjectContext.save()
} catch {
print(error)
}
}
After retrieving latitude, longitude you can use coordinate in your implementations as
let newItem = getCoordinateFromCoreData() // your retrieval function
let coordinate = CLLocationCoordinate2D(latitude: newItem.latitude, longitude: newItem.longitude)
You need to convert the co-ordinate to double/NSdata type and then store it in CoreData. Use NSKeyedArchiver and NSKeyedUnarchiver to store and retrieve the values. CoreData can't store CLLocation object directly.
// Convert CLLocation object to Data
let newPlaceLatitudeArchived = NSKeyedArchiver.archivedDataWithRootObject(newPlaceLatitude)
//CoreData Piece
newPlace.setValue(newPlaceLatitudeArchived, forKeyPath: "latitude")
// fetch the latitude from CoreData as Archive object and pass it to unarchive to get the CLLocation
let newPlaceLatitudeUnArchived = NSKeyedUnarchiver.unarchiveObjectWithData(archivedLocation) as? CLLocation
You will need to convert you attribute to binary type in CoreData in this case.

Checking for parameters for CLLocationCoordinate2DMake

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.

How to make value in func to global constant in Swift

How do I go about setting the long and latitude value (both which display a when app runs) to a global constant? The values are currently
String(format: "4.4f", latestLocation.coordinate.latitude)
and
String(format: "4.4f", latestLocation.coordinate.longitude)
I want to make these a global constant like userlatitude and userlongitude which can be accessed outside the function. Do I have to return someHope that makes sense.
func locationManager(manager: CLLocationManager!,
didUpdateLocations locations: [AnyObject]!)
{
var latestLocation = locations.last as! CLLocation
latitude.text = String(format: "%.4f",
latestLocation.coordinate.latitude)
longitude.text = String(format: "%.4f",
latestLocation.coordinate.longitude)
}
This way you can store Locations to NSUserDefaults:
//First Convert it to NSNumber.
let lat : NSNumber = NSNumber(double: Location.latitude)
let lng : NSNumber = NSNumber(double: Location.longitude)
//Store it into Dictionary
let locationDict = ["lat": lat, "lng": lng]
//Store that Dictionary into NSUserDefaults
NSUserDefaults.standardUserDefaults().setObject(locationDict, forKey: "Location")
After that you can access it this way anywhere you want:
//Access that stored Values
let userLoc = NSUserDefaults.standardUserDefaults().objectForKey("Location") as! [String : NSNumber]
//Get user location from that Dictionary
let userLat = userLoc["lat"]
let userLng = userLoc["lng"]
var Annotation = MKPointAnnotation()
Annotation.coordinate.latitude = userLat as! CLLocationDegrees //Convert NSNumber to CLLocationDegrees
Annotation.coordinate.longitude = userLng as! CLLocationDegrees //Convert NSNumber to CLLocationDegrees
One solution could be that you store the values as NSUserDefaults, which gives you access to the values when you need it. try this link for more information http://www.codingexplorer.com/nsuserdefaults-a-swift-introduction/
Define your Variable Below of import statement. Something Like,
import UIKit
let latitude = 4.0
// Do Stuff - This Variable access in Any class. Thanx Swift....
Another solution is put your value in .plist/NSUser Default and access in every class(Where should you wish to use) using appropriate key.

Convert string to CLLocationCoordinate

Is it possible to convert a string to a longitude/latitude value? I managed to convert the coordinate to a string, but I cannot find a way to revert the process
Another way to convert:
let latitude = (latitudeString as NSString).doubleValue
let longitude = (longitudeString as NSString).doubleValue
Swift 3
let lat = Double(String1)
let lon = Double(String2)
let coordinates = CLLocationCoordinate2D(latitude:lat!
, longitude:lon!)
CLLocationCoordinate2D is a double value it can convert string into double See in above example
My bad, it was a simple type. If anyone ever struggle on how to convert a string to coordinates, here's the correct syntax :
let location:CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: Double(([longitudeString] as NSString).doubleValue), longitude: Double(([LatitudeString] as NSString).doubleValue))
var currentLocationLatitude = "45.5626" // your string latitude
var currentLocationLongitude = "45.5626" // your string longitude
var currentLocation:CLLocationCoordinate2D! //location object
currentLocation = CLLocationCoordinate2D(latitude:currentLocationLatitude.toDouble() ?? 0.0, longitude: currentLocationLongitude.toDouble() ?? 0.0)
extension String
{
/// EZSE: Converts String to Double
public func toDouble() -> Double?
{
if let num = NumberFormatter().number(from: self) {
return num.doubleValue
} else {
return nil
}
}
}
You can take string latitude and longitude from you API response and in CLLocationCoordinate2D variable, pass with converting to Double value.
I have also added extension for converting string to double.
might help
let Latitude = ("41" as NSString).doubleValue
let Longitude = ("29" as NSString).doubleValue

Resources