Getting longitude and latitude - ios

I have experience crash of the app when using it in US. In all other countries same code is working. The crash is happening on line:
let latitude = String(format: "%.7f", currentLocation.coordinate.latitude)
I really can't see what is the problem, specially cos is related to US and not to other counties. Any help will be very very much appreciate.
My UserLocation.swift looks like this:
import UIKit
import MapKit
public class GPSLocation {
static let sharedInstance = GPSLocation()
//MARK: Public variables
public var intermediateLatitude: String?
public var intermediateLongitude: String?
public var intermediateCountry: String?
public var intermediateCity: String?
public var intermediateTimeZone: String?
//MARK: Get Longitude, Country Code and City name
func getGPSLocation(completition: #escaping () -> Void) {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locManager = manager
var currentLocation: CLLocation!
locManager.desiredAccuracy = kCLLocationAccuracyBest
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse || CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways) {
currentLocation = locManager.location
if currentLocation != nil {
// Get longitude & latitude
let latitude = String(format: "%.7f", currentLocation.coordinate.latitude)
let longitude = String(format: "%.7f", currentLocation.coordinate.longitude)
self.intermediateLatitude = latitude
self.intermediateLongitude = longitude
// debugPrint("Latitude:",latitude)
// debugPrint("Longitude:",longitude)
// Get local time zone GMT
let localTimeZoneAbbreviation = TimeZone.current.abbreviation() ?? "" // "GMT-2"
let indexStartOfText = localTimeZoneAbbreviation.index(localTimeZoneAbbreviation.startIndex, offsetBy: 3) // 3
let timeZone = localTimeZoneAbbreviation.substring(from: indexStartOfText) // "-2"
self.intermediateTimeZone = timeZone
// debugPrint("GMT:",timeZone)
// Get Country code and City
let location = CLLocation(latitude: currentLocation.coordinate.latitude, longitude: currentLocation.coordinate.longitude)
fetchCountryAndCity(location: location) { countryCode, city in
self.intermediateCountry = countryCode
self.intermediateCity = city
// debugPrint("Country code:",countryCode)
// debugPrint("City:",city)
completition()
}
} else {
// Location is NIL
}
}
}
locManager.delegate = self // and conform protocol
locationManager.startUpdatingLocation()
}
//MARK: Find countryCode & City name from longitude & latitude
func fetchCountryAndCity(location: CLLocation, completion: #escaping (String, String) -> ()) {
CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in
if let error = error {
debugPrint(error)
} else if let countryCode = placemarks?.first?.isoCountryCode,
let city = placemarks?.first?.locality {
completion(countryCode, city)
}
}
}
}

You need to check location in delegate method
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.stopUpdatingLocation() // if you dont want continuously update
currentLocation = manager.location
let location = CLLocation(latitude: currentLocation.coordinate.latitude, longitude: currentLocation.coordinate.longitude)
fetchCountryAndCity(location: location) { countryCode, city in
self.intermediateCountry = countryCode
self.intermediateCity = city
// debugPrint("Country code:",countryCode)
// debugPrint("City:",city)
completition()
}
}
And set delegate
locManager.delegate = self // and conform protocol
locationManager.startUpdatingLocation()

Related

Return Type Nill

func getAddressFromLatLon() {
var locManager = CLLocationManager()
locManager.requestWhenInUseAuthorization()
var currentLocation = CLLocation()
if( CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorized){
currentLocation = locManager.location!
}
var center : CLLocationCoordinate2D = CLLocationCoordinate2D()
let lat: Double = Double(currentLocation.coordinate.latitude)
//21.228124
let lon: Double = Double(currentLocation.coordinate.longitude)
//72.833770
let ceo: CLGeocoder = CLGeocoder()
center.latitude = lat
center.longitude = lon
let geoCoder = CLGeocoder()
var placemark: AnyObject
var error: NSError
geoCoder.reverseGeocodeLocation(locManager.location!, completionHandler: { (placemark, error) -> Void in
if error != nil {
print("Error: \(error?.localizedDescription)")
return
}
if (placemark?.count)! > 0 {
let pm = (placemark?[0])! as CLPlacemark
//self.addressString = pm.locality! + pm.country!
let adress = pm.locality! + " " + pm.country!
print(adress)
} else {
print("Error with data")
}
})
}
Sorry about this very basic question. I am fairly new to swift and I am trying to reverse geocode a latitude and longitude. I am trying to return the adress from the reverse geocoding, but it seems to be returning nil. The function in question is getAddressFromLatLon() and I have tried adding a return type but it is returning nil. When I print in the function itself, the correct value is printed but for some reason I am having difficulty getting the adress to return so I can pass it to other classes/functions.
You need to hold the value which you get from reserver geocoder and just need to use it.
geoCoder.reverseGeocodeLocation(locManager.location!, completionHandler: { (placemark, error) -> Void in
if error != nil {
print("Error: \(error?.localizedDescription)")
return
}
if (placemark?.count)! > 0 {
let pm = (placemark?[0])! as CLPlacemark
//self.addressString = pm.locality! + pm.country!
let adress = pm.locality! + " " + pm.country!
// Store value into global object and you can use it...
// Another option, you can call one function and do necessary steps in it
mainLocality = pm.locality
mainCountry - pm.country
updateGeoLocation() // Call funcation
print(adress)
} else {
print("Error with data")
}
})
func updateGeoLocation(){
// You can use both object at here
// mainLocality
// mainCountry
// Do your stuff
}
You need to initilise CLLocation object in ViewDidLoad and get location coordinatites in it delegate method
Declate variable for current location
var currentLocation : CLLocation
In ViewDidLoad
var locManager = CLLocationManager()
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
// ask permission - NOT NECESSARY IF YOU ALREADY ADDED NSLocationAlwaysUsageDescription IT UP INFO.PLIST
locationManager.requestAlwaysAuthorization()
// when in use foreground
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
CLLocation's Delegate
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// Get first location item returned from locations array
currentLocation = locations[0]
self.getAddressFromLatLon() // you can call here or whenever you want
}
Your method as below
func getAddressFromLatLon() {
var center : CLLocationCoordinate2D = CLLocationCoordinate2D()
let lat: Double = Double(currentLocation.coordinate.latitude)
//21.228124
let lon: Double = Double(currentLocation.coordinate.longitude)
//72.833770
let ceo: CLGeocoder = CLGeocoder()
center.latitude = lat
center.longitude = lon
let geoCoder = CLGeocoder()
var placemark: AnyObject
var error: NSError
geoCoder.reverseGeocodeLocation(locManager.location!, completionHandler: { (placemark, error) -> Void in
if error != nil {
print("Error: \(error?.localizedDescription)")
return
}
if (placemark?.count)! > 0 {
let pm = (placemark?[0])! as CLPlacemark
//self.addressString = pm.locality! + pm.country!
let adress = pm.locality! + " " + pm.country!
print(adress)
} else {
print("Error with data")
}
})
}

Pass longitude and latitude from CLLocationManager to URL?

i'm trying to pass my latitude and longitude to my url params but is returning Nil, but when i print within the delegate it returns the longitude and latitude and i can't seem to find the issue, i've tried many different ways and nothing seems to work
this are the variable where i store my latitude and longitude
var lat: Double!
var long: Double!
this is my delegate
func locationManager(_ manager:CLLocationManager, didUpdateLocations locations: [CLLocation]){
currentLocation = manager.location!.coordinate
let locValue:CLLocationCoordinate2D = currentLocation!
self.long = locValue.longitude
self.lat = locValue.latitude
print(lat)
print(long)
}
and here pass them to variables i'm using in my URL parameters but they return nil and i don't understand why
let userLat = String(describing: lat)
let userLong = String(describing: long)
Thank You
Try something like:
Swift 3
func locationManager(_ manager:CLLocationManager, didUpdateLocations locations: [CLLocation]){
if let last = locations.last {
sendLocation(last.coordinate)
}
}
func sendLocation(_ coordinate: CLLocationCoordinate2D) {
let userLat = NSString(format: "%f", coordinate.latitude) as String
let userLong = NSString(format: "%f", coordinate.longitude) as String
// Run API Call....
}
I think the Joseph K's answer is not correct. It rounds off the values of the latitude and longitude. It will be something like the code below.
let coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(exactly: 35.6535425)!, longitude: CLLocationDegrees(exactly: 139.7047917)!)
let latitude = coordinate.latitude // 35.6535425
let longitude = coordinate.longitude // 139.7047917
let latitudeString = NSString(format: "%f", latitude) as String // "35.653543"
let longitudeString = NSString(format: "%f", longitude) as String // "139.704792"
So the correct and simpler code is:
Swift 3
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let coordinate = locations.last?.coordinate else { return }
let latitude = "\(coordinate.latitude)"
let longitude = "\(coordinate.longitude)"
// Do whatever you want to make a URL.
}

Find city name and country from latitude and longitude in Swift

I'm working on application in Swift3
and I have letter problem i can't find the answer for it.
How can I know city name and country short names base on latitude and longitude?
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate{
let locationManager = CLLocationManager()
var latitude: Double = 0
var longitude: Double = 0
override func viewDidLoad() {
super.viewDidLoad()
// For use when the app is open & in the background
locationManager.requestAlwaysAuthorization()
// For use when the app is open
//locationManager.requestWhenInUseAuthorization()
locationManager.delegate = self
locationManager.startUpdatingLocation()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
print(location.coordinate)
latitude = location.coordinate.latitude
longitude = location.coordinate.longitude
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if (status == CLAuthorizationStatus.denied){
showLocationDisabledpopUp()
}
}
func showLocationDisabledpopUp() {
let alertController = UIAlertController(title: "Background Location Access Disabled", message: "We need your location", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
let openAction = UIAlertAction(title: "Open Setting", style: .default) { (action) in
if let url = URL(string: UIApplicationOpenSettingsURLString){
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
alertController.addAction(openAction)
self.present(alertController, animated: true, completion: nil)
}
}
You can use CLGeocoder reverseGeocodeLocation method to fetch a CLPlacemark and get its country and locality properties info. Note that it is an asynchronous method so you will need to add a completion handler to your method when fetching that info:
import UIKit
import MapKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
extension CLLocation {
func fetchCityAndCountry(completion: #escaping (_ city: String?, _ country: String?, _ error: Error?) -> ()) {
CLGeocoder().reverseGeocodeLocation(self) { completion($0?.first?.locality, $0?.first?.country, $1) }
}
}
Usage
let location = CLLocation(latitude: -22.963451, longitude: -43.198242)
location.fetchCityAndCountry { city, country, error in
guard let city = city, let country = country, error == nil else { return }
print(city + ", " + country) // Rio de Janeiro, Brazil
}
edit/update:
iOS 11 or later CLPlacemark has a postalAddress property. You can import Contacts framework and use CNPostalAddressFormatter's string(from:) method to get a localized formatted address. You can also extend CLPlacemark and add some computed properties to better describe some of its properties:
import MapKit
import Contacts
extension CLPlacemark {
/// street name, eg. Infinite Loop
var streetName: String? { thoroughfare }
/// // eg. 1
var streetNumber: String? { subThoroughfare }
/// city, eg. Cupertino
var city: String? { locality }
/// neighborhood, common name, eg. Mission District
var neighborhood: String? { subLocality }
/// state, eg. CA
var state: String? { administrativeArea }
/// county, eg. Santa Clara
var county: String? { subAdministrativeArea }
/// zip code, eg. 95014
var zipCode: String? { postalCode }
/// postal address formatted
#available(iOS 11.0, *)
var postalAddressFormatted: String? {
guard let postalAddress = postalAddress else { return nil }
return CNPostalAddressFormatter().string(from: postalAddress)
}
}
extension CLLocation {
func placemark(completion: #escaping (_ placemark: CLPlacemark?, _ error: Error?) -> ()) {
CLGeocoder().reverseGeocodeLocation(self) { completion($0?.first, $1) }
}
}
Usage:
let location = CLLocation(latitude: 37.331676, longitude: -122.030189)
location.placemark { placemark, error in
guard let placemark = placemark else {
print("Error:", error ?? "nil")
return
}
print(placemark.postalAddressFormatted ?? "")
}
This will print
1 Infinite Loop
Cupertino CA 95014
United States
I would recommend integrating Google Maps API with your project. If you do, your task can be achieved using Reverse Geocoding Google provides.
Furthermore, Google there is Google Maps SDK for IOS development, which is also worth considering.
UPD: You can do that without integrating maps into your project. Basing on this answer, you can achieve that using http requests to Google API. The request to:
https://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&key=API_KEY
would return JSON object with information about the requested place, including country and city name.
BTW, I highly recommend using Alamofire to make http requests in Swift.
What you need is called reverse geocoding. As you have already declared some properties at the top. You need to add the CLGeocoder & CLPlancemark
let locationManager = CLLocationManager()
var location: CLLocation?
let geocoder = CLGeocoder()
var placemark: CLPlacemark?
// here I am declaring the iVars for city and country to access them later
var city: String?
var country: String?
var countryShortName: String?
Create a function where you can start the location services
func startLocationManager() {
// always good habit to check if locationServicesEnabled
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
}
also create another to stop once you're done with location geocoding
func stopLocationManager() {
locationManager.stopUpdatingLocation()
locationManager.delegate = nil
}
in view didLoad or from anywhere you want to start the location manager add a check first
override func viewDidLoad() {
super.viewDidLoad()
let authStatus = CLLocationManager.authorizationStatus()
if authStatus == .notDetermined {
locationManager.requestWhenInUseAuthorization()
}
if authStatus == .denied || authStatus == .restricted {
// add any alert or inform the user to to enable location services
}
// here you can call the start location function
startLocationManager()
}
implement the delegate methods for location manager didFailedWithError
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
// print the error to see what went wrong
print("didFailwithError\(error)")
// stop location manager if failed
stopLocationManager()
}
implement the delegate method for location manager didUpdateLocations
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// if you need to get latest data you can get locations.last to check it if the device has been moved
let latestLocation = locations.last!
// here check if no need to continue just return still in the same place
if latestLocation.horizontalAccuracy < 0 {
return
}
// if it location is nil or it has been moved
if location == nil || location!.horizontalAccuracy > lastLocation.horizontalAccuracy {
location = lastLocation
// stop location manager
stopLocationManager()
// Here is the place you want to start reverseGeocoding
geocoder.reverseGeocodeLocation(lastLocation, completionHandler: { (placemarks, error) in
// always good to check if no error
// also we have to unwrap the placemark because it's optional
// I have done all in a single if but you check them separately
if error == nil, let placemark = placemarks, !placemark.isEmpty {
self.placemark = placemark.last
}
// a new function where you start to parse placemarks to get the information you need
self.parsePlacemarks()
})
}
}
Add the parsePlacemarks function
parsePlacemarks() {
// here we check if location manager is not nil using a _ wild card
if let _ = location {
// unwrap the placemark
if let placemark = placemark {
// wow now you can get the city name. remember that apple refers to city name as locality not city
// again we have to unwrap the locality remember optionalllls also some times there is no text so we check that it should not be empty
if let city = placemark.locality, !city.isEmpty {
// here you have the city name
// assign city name to our iVar
self.city = city
}
// the same story optionalllls also they are not empty
if let country = placemark.country, !country.isEmpty {
self.country = country
}
// get the country short name which is called isoCountryCode
if let countryShortName = placemark.isoCountryCode, !countryShortName.isEmpty {
self.countryShortName = countryShortName
}
}
} else {
// add some more check's if for some reason location manager is nil
}
}
You have to cmd+click on CLPlacemark to see all the properties that you can access for example street name is called thoroughfare & the number is is called subThoroughfare continue reading the documentation for more information
Note: You have to check for locations error also geocoder error which I haven't implemented here but you have to take care of those errors and the best place to check error codes and everything else is apples documentation
Update: Check paresPlacemarks function where I added isoCountryCode which is equal to country shortName No need to add extra network calls to google API and Alamofire while your already using location services
Here is the Swift 4 code:
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
locationManager.startMonitoringSignificantLocationChanges()
// Here you can check whether you have allowed the permission or not.
if CLLocationManager.locationServicesEnabled()
{
switch(CLLocationManager.authorizationStatus())
{
case .authorizedAlways, .authorizedWhenInUse:
print("Authorize.")
let latitude: CLLocationDegrees = (locationManager.location?.coordinate.latitude)!
let longitude: CLLocationDegrees = (locationManager.location?.coordinate.longitude)!
let location = CLLocation(latitude: latitude, longitude: longitude) //changed!!!
CLGeocoder().reverseGeocodeLocation(location, completionHandler: {(placemarks, error) -> Void in
if error != nil {
return
}else if let country = placemarks?.first?.country,
let city = placemarks?.first?.locality {
print(country)
self.cityNameStr = city
}
else {
}
})
break
case .notDetermined:
print("Not determined.")
self.showAlertMessage(messageTitle: "Bolo Board", withMessage: "Location service is disabled!!")
break
case .restricted:
print("Restricted.")
self.showAlertMessage(messageTitle: "Bolo Board", withMessage: "Location service is disabled!!")
break
case .denied:
print("Denied.")
}
}
}
func showAlertMessage(messageTitle: NSString, withMessage: NSString) ->Void {
let alertController = UIAlertController(title: messageTitle as String, message: withMessage as String, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action:UIAlertAction!) in
}
alertController.addAction(cancelAction)
let OKAction = UIAlertAction(title: "Settings", style: .default) { (action:UIAlertAction!) in
if let url = URL(string: "App-Prefs:root=Privacy&path=LOCATION/com.company.AppName") {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
// Fallback on earlier versions
}
}
}
alertController.addAction(OKAction)
self.present(alertController, animated: true, completion:nil)
}
You can use CLGeocoder, from CoreLocation, for that. From Apple documentation (emphasizes mine):
A single-shot object for converting between geographic coordinates and place names.
The CLGeocoder class provides services for converting between a coordinate (specified as a latitude and longitude) and the user-friendly representation of that coordinate. A user-friendly representation of the coordinate typically consists of the street, city, state, and country information corresponding to the given location...
This service is unrelated to MapKit and, as such, don't require you use/show a map in your app at all.
import Foundation
import CoreLocation
let location = CLLocation(latitude: 37.3321, longitude: -122.0318)
CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in
guard let placemark = placemarks?.first else {
let errorString = error?.localizedDescription ?? "Unexpected Error"
print("Unable to reverse geocode the given location. Error: \(errorString)")
return
}
let reversedGeoLocation = ReversedGeoLocation(with: placemark)
print(reversedGeoLocation.formattedAddress)
// Apple Inc.,
// 1 Infinite Loop,
// Cupertino, CA 95014
// United States
}
struct ReversedGeoLocation {
let name: String // eg. Apple Inc.
let streetName: String // eg. Infinite Loop
let streetNumber: String // eg. 1
let city: String // eg. Cupertino
let state: String // eg. CA
let zipCode: String // eg. 95014
let country: String // eg. United States
let isoCountryCode: String // eg. US
var formattedAddress: String {
return """
\(name),
\(streetNumber) \(streetName),
\(city), \(state) \(zipCode)
\(country)
"""
}
// Handle optionals as needed
init(with placemark: CLPlacemark) {
self.name = placemark.name ?? ""
self.streetName = placemark.thoroughfare ?? ""
self.streetNumber = placemark.subThoroughfare ?? ""
self.city = placemark.locality ?? ""
self.state = placemark.administrativeArea ?? ""
self.zipCode = placemark.postalCode ?? ""
self.country = placemark.country ?? ""
self.isoCountryCode = placemark.isoCountryCode ?? ""
}
}
1 . import CoreLocation
2 . insert CLLocationManagerDelegate in your class
3 . Do the delegate methods described below... hope it will help you
you can find city name and country through following these steps...Here is my code
import UIKit
import CoreLocation
class MyViewController:UIViewController,CLLocationManagerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if( CLLocationManager.authorizationStatus() == .authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == .authorizedAlways){
if let currentLocation = locationManager.location
{
if NetworkFunctions.NetworkRechability()
{
getAddressFromLatLon(pdblLatitude: "\(Double((currentLocation.coordinate.latitude)))", withLongitude: "\(Double((currentLocation.coordinate.longitude)))")
}
}
}
}
func getAddressFromLatLon(pdblLatitude: String, withLongitude pdblLongitude: String) {
var center : CLLocationCoordinate2D = CLLocationCoordinate2D()
let lat: Double = Double("\(pdblLatitude)")!
let lon: Double = Double("\(pdblLongitude)")!
let ceo: CLGeocoder = CLGeocoder()
center.latitude = lat
center.longitude = lon
let loc: CLLocation = CLLocation(latitude:center.latitude, longitude: center.longitude)
ceo.reverseGeocodeLocation(loc, completionHandler:
{(placemarks, error) in
if (error != nil)
{
}
if placemarks != nil
{
let pm = placemarks! as [CLPlacemark]
if pm.count > 0 {
let pm = placemarks![0]
print(pm.country ?? "")
print(pm.locality ?? "")
print(pm.subLocality ?? "")
print(pm.thoroughfare ?? "")
print(pm.postalCode ?? "")
print(pm.subThoroughfare ?? "")
var addressString : String = ""
if pm.subLocality != nil {
addressString = addressString + pm.subLocality! + ", "
}
if pm.thoroughfare != nil {
addressString = addressString + pm.thoroughfare! + ", "
}
if pm.locality != nil {
addressString = addressString + pm.locality! + ", "
if pm.country != nil {
addressString = addressString + pm.country! + ", "
//uuuuu
if(location_city != pm.locality!.trimmingCharacters(in: .whitespaces))
{
location_city=pm.locality!.trimmingCharacters(in: .whitespaces)
DispatchQueue.main.async{
self.GetBeeWatherDetails(district: pm.locality!, country: pm.country!)
}
}
}
}
if pm.postalCode != nil {
addressString = addressString + pm.postalCode! + " "
}
}
}
})
}
}
Add this extension in your swift file.
extension CLLocation {
func fetchAddress(completion: #escaping (_ address: String?, _ error: Error?) -> ()) {
CLGeocoder().reverseGeocodeLocation(self) {
let palcemark = $0?.first
var address = ""
if let subThoroughfare = palcemark?.subThoroughfare {
address = address + subThoroughfare + ","
}
if let thoroughfare = palcemark?.thoroughfare {
address = address + thoroughfare + ","
}
if let locality = palcemark?.locality {
address = address + locality + ","
}
if let subLocality = palcemark?.subLocality {
address = address + subLocality + ","
}
if let administrativeArea = palcemark?.administrativeArea {
address = address + administrativeArea + ","
}
if let postalCode = palcemark?.postalCode {
address = address + postalCode + ","
}
if let country = palcemark?.country {
address = address + country + ","
}
if address.last == "," {
address = String(address.dropLast())
}
completion(address,$1)
// completion("\($0?.first?.subThoroughfare ?? ""), \($0?.first?.thoroughfare ?? ""), \($0?.first?.locality ?? ""), \($0?.first?.subLocality ?? ""), \($0?.first?.administrativeArea ?? ""), \($0?.first?.postalCode ?? ""), \($0?.first?.country ?? "")",$1)
}
}
}
And then call it on any of the CLLocation object.
Eg:
(myLocation as? CLLocation)!.fetchAddress { (address, error) in
guard let address = address, error == nil else
{return }
I had also the same issue .You can use this code.
func placePicker(_ viewController: GMSPlacePickerViewController, didPick place: GMSPlace) {
viewController.dismiss(animated: true, completion: nil)
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude)
geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
// Place details
var placeMark: CLPlacemark!
placeMark = placemarks?[0]
// Address dictionary
print(placeMark.addressDictionary as Any)
//
print("Place name \(place.name)")
print("Place address \(String(describing: place.formattedAddress))")
print("Place attributions \(String(describing: place.attributions))")
})
}
Hope this will resolve your problem.
This method will give you the current location, city name ,country name etc.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location: CLLocation = locations.last!
print("Location: \(location)")
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(location) { (placemarks, error) in
// Process Response
if let error = error {
print("Unable to Reverse Geocode Location (\(error))")
} else {
if let placemarks = placemarks, let placemark = placemarks.first {
self.city = placemark.locality!
//self.country = placemark.country!
}
}
}
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
longitude: location.coordinate.longitude,
zoom: zoomLevel)
self.locationv = CLLocation(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
if myView.isHidden {
myView.isHidden = false
myView.camera = camera
} else {
myView.animate(to: camera)
}
}
See my answer in swift 4.1 Xcode 9.4.1. You can get even village name details also. Get location name from Latitude & Longitude in iOS

How to calculate the distance between my current location and other Pins in MapView

I am new to Swift and I need to calculate the nearest places around my current location. Would you advice me which function should I use to calculate the distance between my location and the nearest around me. I have to display the distance and the places in the app,so that the user can choose which one fits best for him.I think I should use latitude and longitude coordinates which can be compared with mine. I also found out that I have to use distanceFromLocation , but I do not know how and I would be glad if someone provide me with an example which I can use for my code.
My code so far is:
class ViewThree: UIViewController, CLLocationManagerDelegate{
#IBOutlet weak var SegmentControl: UISegmentedControl!
#IBOutlet weak var Mapview: MKMapView!
var manager = CLLocationManager()
var receiveImeNaSladkarnica: String = ""
var KordaA: String = ""
var KordaB: String = ""
var PodImeNaObekt: String = ""
override func viewDidLoad() {
super.viewDidLoad()
let pinLocation: CLLocationCoordinate2D = CLLocationCoordinate2DMake((KordaA as NSString).doubleValue,(KordaB as NSString).doubleValue)
let objectAnn = MKPointAnnotation()
objectAnn.coordinate = pinLocation
objectAnn.title = receiveImeNaSladkarnica
objectAnn.subtitle = PodImeNaObekt
self.Mapview.addAnnotation(objectAnn)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func Directions(sender: AnyObject) {
UIApplication.sharedApplication().openURL(NSURL(string: "http://maps.apple.com/maps?daddr=\((KordaA as NSString).doubleValue),\((KordaB as NSString).doubleValue))")!)
}
#IBAction func MapType(sender: AnyObject) {
if (SegmentControl.selectedSegmentIndex == 0){
Mapview.mapType = MKMapType.Standard
}
if (SegmentControl.selectedSegmentIndex == 1){
Mapview.mapType = MKMapType.Satellite
}
}
#IBAction func LocateMe(sender: AnyObject) {
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
Mapview.showsUserLocation = true
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userlocation: CLLocation = locations[0] as CLLocation
manager.stopUpdatingLocation()
let location = CLLocationCoordinate2D(latitude: userlocation.coordinate.latitude, longitude: userlocation.coordinate.longitude)
let span = MKCoordinateSpanMake(0.5, 0.5)
let region = MKCoordinateRegion(center: location, span: span)
Mapview.setRegion(region, animated: true )
}
I had the same scenario with an other app.
Within the CLLocation object, there is an instance function:
func distanceFromLocation(location: CLLocation) -> CLLocationDistance
//Get your two locations that you want to calculate the distance from:
let userLocation: CLLocation = ...
let locationToCompare: CLLocation = ...
// Returned value is in meters
let distanceMeters = userLocation.distanceFromLocation(locationToCompare)
// If you want to round it to kilometers
let distanceKilometers = distanceMeters / 1000.00
// Display it in kilometers
let roundedDistanceKilometers = String(Double(round(100 * distanceKilometers) / 100)) + " km"
UPDATED
For your use case
let locations = ... // All locations you want to compare
for location in locations {
let distanceMeters = userLocation.distanceFromLocation(location)
if distanceMeters > 5000 { // Some distance filter
// Don't display this location
} else {
// Display this location
}
}
MY CODE:
IMPROVED
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userlocation:CLLocation = locations[0] as CLLocation
manager.stopUpdatingLocation()
let location = CLLocationCoordinate2D(latitude: userlocation.coordinate.latitude, longitude: userlocation.coordinate.longitude)
let span = MKCoordinateSpanMake(0.5, 0.5)
let region = MKCoordinateRegion(center: location, span: span)
Mapview.setRegion(region, animated: true)
let locationStrings = ["42.6977,23.3219","43.6977,24.3219"]
// This array must be an array that contains CLLocation objects
var locations: [CLLocation] = []
// We must retrieve the latitude and longitude from locationStrings array to convert them into CLLocation objects
for locationString in locationStrings {
let location = CLLocation(latitude: <latitude_value>, longitude: <latitude_value>)
locations.append(location)
}
// Then you will be able to enumerate through the array
for location in locations {
let distanceMeters = userLocation.distanceFromLocation(location)
if distanceMeters > 5000 { // Some distance filter
// Don't display this location
} else {
// Display this location
}
}
You can use distanceFromLocation method to get distance
let distance = userlocation.distanceFromLocation(YourPinInMap)
locA = [[CLLocation alloc] initWithLatitude:[[[NSUserDefaults standardUserDefaults]valueForKey:#"startLat"]floatValue] longitude:[[[NSUserDefaults standardUserDefaults]valueForKey:#"startlong"]floatValue]];
locB = [[CLLocation alloc] initWithLatitude:[[[NSUserDefaults standardUserDefaults]valueForKey:#"destLat"]floatValue] longitude:[[[NSUserDefaults standardUserDefaults]valueForKey:#"destLong"]floatValue]];
distance = [locA distanceFromLocation:locB];
where locA and locB are CLLocation type pass the lat long over there

Swift - Return value from locationManager function in class extension

I'm trying to get directions from the users current location to a destination using Google Maps. I want this to be done when the showDirection button is pressed, however I can't figure how to return or pass the users location into the IBAction function from func locationManager(... didUpdateLocation) as the IBAction doesn't use parameters in which I can pass locValue to.
Here is the showDirection button function:
#IBAction func showDirection(sender: AnyObject) {
print("Running showDirection")
let instanceOne = ParseViewController() // Create ParseViewController instance to operate on
print("Created ParseView instance")
let Coord = instanceOne.returnParse()
let latitude = (Coord.lat as NSString)
let longitude = (Coord.long as NSString)
var urlString = "http://maps.google.com/maps?"
urlString += "saddr= // Users location from didUpdateLocation"
urlString += "&daddr= \(latitude as String), \(longitude as String)"
print(urlString)
if let url = NSURL(string: urlString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
{
UIApplication.sharedApplication().openURL(url)
}
}
and here is the locationManager function with the locValue:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)
let locValue:CLLocationCoordinate2D = (manager.location?.coordinate)!
print("Coordinates = \(locValue.latitude), \(locValue.longitude)")
locationManager.stopUpdatingLocation()
}
}
Any help is greatly appreciated!
You need to create an internal variable in the class to store the location if you want to use it in another function. E.g.
class YourViewController: UIViewController ... {
var lastLocation: CLLocation? = nil
...
}
In didUpdateLocations:
if let location = locations.first {
lastLocation = location
...
}
And now you can access it in func showDirection()

Resources