Obtaining iPhone Latitude & Longitude - ios

I've been attempting to retrieve a iPhone's latitude and longitude for purposes of passing to an external function in order to geotag something. However, I've been rather unsuccessful. Here is the code I'm working with right now.
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func findMyLocation (sender:AnyObject)
{
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
{
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: {(placemarks, error)->Void in
if error == nil
{
println("Reverse geocoder failed with error " + error.localizedDescription)
return
}
if placemarks.count > 0
{
let pm = placemarks[0] as CLPlacemark
self.displayLocationInfo(pm)
}
else
{
println("Problem with the data received from geocoder")
}
})
}
func displayLocationInfo(placemark: CLPlacemark) {
//stop updating location to save battery life
locationManager.stopUpdatingLocation()
if (placemark.postalCode != nil)
{
println(placemark.postalCode)
println("just tried to print placemark's postal code")
}
//println(placemark.locality ? placemark.locality : "")
//println(placemark.postalCode ? placemark.postalCode : "")
//println(placemark.administrativeArea ? placemark.administrativeArea : "")
//println(placemark.country ? placemark.country : "")
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!)
{
println("Error while updating location " + error.localizedDescription)
}
As of now, I get pretty much nothing when I run the program. I have a little button that says "Find Me", and upon clicking, nothing pops up in the output box. I have the iOS Simulator's Debug location set to "Apple", and I've previously tried always enabling location services in settings on the simulator when trying to run the program (although currently it's not showing my app and the option to do so).
I really just want to get a double value for latitude and longitude, and if there's a simple something that'd be great.

You should only request one type of authorization. Pick the one that makes the most sense for the user experience of your app.
You are probably missing your purpose string, which is now required to activate location services. Add one of the following keys to your Info.plist:
NSLocationAlwaysUsageDescription - if requesting Always permission
NSLocationWhenInUseUsageDescription - if requesting WhenInUse permission
The value of the key should be a string that explains why you want location permissions.

Related

iOS permissions for user location

I am just creating an iOS app that needs to get the user location.
I have included the needed keys and values into info.plist like shown in the screenshot:
but when running the app there is a message in the debugger:
2020-04-25 18:51:16.395466+0200 Jogua[23008:1151035] This app has attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain both “NSLocationAlwaysAndWhenInUseUsageDescription” and “NSLocationWhenInUseUsageDescription” keys with string values explaining to the user how the app uses this data
Do I need to change anything else in the code?
EDIT
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
determineMyCurrentLocation()
}
func determineMyCurrentLocation() {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation:CLLocation = locations[0] as CLLocation
print("user latitude = \(userLocation.coordinate.latitude)")
self.defaults.set(userLocation.coordinate.latitude, forKey: "mi_latitud")
print("user longitude = \(userLocation.coordinate.longitude)")
self.defaults.set(userLocation.coordinate.longitude, forKey: "mi_longitud")
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error)
{
print("Error \(error)")
}
As your debugger says, you are missing one entry in your info.plist. It can be misleading because the name the console prints, is not the actual key name inside info.plist.
You added:
Privacy - Location Always Usage Description
Privacy - Location Usage Description
Privacy - Location Always and When In Use Usage Description
What you need according to the debugger is:
Privacy - Location When In Use Usage Description
Privacy - Location Always and When In Use Usage Description
What you need to add in your case:
Privacy - Location When In Use Usage Description

SWIFT - LocationManager looping through multiple times?

I have a locationManager function to grab the users current location and posting the name of the city and state. I have a print statement so I can check in my console if everything is working properly...and it is. However, it prints the city location 3 times. This actually causes an issue in my actual app but thats beyond the point of this question.
My function is as follows:
var usersLocation: String!
var locationManager: CLLocationManager!
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation: CLLocation = locations[0]
CLGeocoder().reverseGeocodeLocation(userLocation) { (placemarks, error) -> Void in
if error != nil {
print(error)
} else {
let p = placemarks?.first // ".first" returns the first element in the collection, or nil if its empty
// this code above will equal the first element in the placemarks array
let city = p?.locality != nil ? p?.locality : ""
let state = p?.administrativeArea != nil ? p?.administrativeArea : ""
self.navigationBar.title = ("\(city!), \(state!)")
self.usersLocation = ("\(city!), \(state!)")
self.locationManager.stopUpdatingLocation()
print(self.usersLocation)
self.refreshPosts()
}
}
}
So in my print(self.usersLocation) it will print in my console three times. Is this normal?
UPDATE TO SHOW VIEWDIDLOAD
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 250.0
}
I'd first suggest a few things:
Call stopUpdatingLocation before you perform reverseGeocodeLocation.
You are calling stopUpdatingLocation inside the reverseGeocodeLocation completion handler closure. The problem is that this runs asynchronously, and thus didUpdateLocations may receive additional location updates in the intervening period. And often, when you first start location services, you'll get a number of updates, often with increasing accuracy (e.g. horizontalAccuracy values that are smaller and smaller). If you turn off location services before initiating asynchronous geocode request, you'll minimize this issue.
You can also add add a distanceFilter in viewDidLoad, which will minimize redundant calls to the delegate method:
locationManager.distanceFilter = 1000
You can use your own state variable that checks to see if the reverse geocode process has been initiated. For example:
private var didPerformGeocode = false
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// if we don't have a valid location, exit
guard let location = locations.first where location.horizontalAccuracy >= 0 else { return }
// or if we have already searched, return
guard !didPerformGeocode else { return }
// otherwise, update state variable, stop location services and start geocode
didPerformGeocode = true
locationManager.stopUpdatingLocation()
CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in
let placemark = placemarks?.first
// if there's an error or no placemark, then exit
guard error == nil && placemark != nil else {
print(error)
return
}
let city = placemark?.locality ?? ""
let state = placemark?.administrativeArea ?? ""
self.navigationBar.title = ("\(city), \(state)")
self.usersLocation = ("\(city), \(state)")
print(self.usersLocation)
self.refreshPosts()
}
}
I had the same problem and Rob's answer didn't do it for me.
When the location service first starts, the location is updated multiple times regardless of the distanceFilter.
You might still want the location to be updated and you don't want to lose the location accuracy(which is the whole point of updating location multiple times on start-up), so calling stopUpdatingLocation(or using a local variable) after the first geolocating call isn't the way to go either.
The most intuitive way is to wrap your geocode call in an #objc function and call the the function with a delay:
NSObject.cancelPreviousPerformRequests(withTarget: self)
perform(#selector(myGeocodeFunction(_:)), with: location, afterDelay: 0.5)

Buttons in allow access to your location disabled

my viewController looks like following
import CoreLocation
class MyViewController: UIViewController {
let locationManager = CLLocationManager()
override func viewDidAppear(animated: Bool) {
if #available(iOS 8.0, *) {
self.locationManager.requestWhenInUseAuthorization()
} else {
// Fallback on earlier versions
}
if (CLLocationManager.locationServicesEnabled()) {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
let lon = locationManager.location!.coordinate.longitude
let lat = locationManager.location!.coordinate.latitude
print("lat = \(lat) and long = \(lon)")
}
}
}
// MARK: - CLLocationManagerDelegate
extension MyViewController : CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("\(error.localizedDescription)")
}
}
When I execute my program, it prompts a message like
Allow application to access your location while you use the app?
But the Don't Allow and Allow buttons are disabled.
Can someone guide me on where I am going wrong and what I should be doing.
I can manually allow my application to access location services by going to settings. But I would like to know why the buttons are disabled and what should I do to enable it.
note: I have added NSLocationWhenInUseUsageDescription to my info.plist file.
Thanks.
Dt: 29Oct2015
EDIT:
Uninstalled the app and installed again and tried. Now I am able to access the buttons.
Also, I noticed that sometimes the screen goes unresponsive i.e., screen cannot take any input from user. I noticed it today with a textbox. I am not able to get the cursor to the text box.
Is it something to do with IOS update? is anyone else experiencing this type of weird behaviour. Is there any workaround for the same?
Any help is highly appreciated.
Thanks.

Swift CLLocation does not update location at startup

I have an application were I want to get the users location in viewDidLoad, I then store the lat and long in variables and use them in a function to get data based on the position from the user. I have a timer that calls a function every x minute that gets data (let´s call it getData()), the first time getData() is called lat and long is 0, but the second, third time etc.. they have values.
When I update the coords (during runtime) in the simulator I do get the updated values for both lat and long, but it´s the first run that lat and long always are 0. My code looks like this:
let locationManager = CLLocationManager()
var getDataGroup = dispatch_group_create()
override func viewDidLoad() {
super.viewDidLoad()
dispatch_group_enter(getDataGroup)
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
dispatch_group_leave(getDataGroup)
dispatch_group_wait(getDataGroup, DISPATCH_TIME_FOREVER)
dispatch_async(dispatch_get_main_queue()) {
self.getData()
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: { (placemarks, error) -> Void in
if (error != nil){
println("Error: " + error.localizedDescription)
return
}
if (placemarks.count > 0){
let pm = placemarks[0] as! CLPlacemark
self.displayLocationInfo(pm)
}
else{
println("Error with location data")
}
})
}
func displayLocationInfo (placemark : CLPlacemark){
self.locationManager.stopUpdatingLocation()
lat = String(stringInterpolationSegment: placemark.location.coordinate.latitude)
long = String(stringInterpolationSegment: placemark.location.coordinate.longitude)
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println("Error: " + error.localizedDescription)
}
func getData(){
// Do stuff with lat and long...
}
For some reason the first run lat and long are both 0, the rest of the runs they have a valid value. The problem is that getData is called before the locationManager and displayLocationInfo methods even though I have added self.locationManager.startUpdatingLocation() before the call to getData() for some reason.
I don't really understand what your code is supposed to do.
There's no reason for the GCD code in your viewDidLoad. simply create an instance of the location manager and tell it to start updating your location.
Then your didUpdateLocations method will be called once a location is available. Use the last location in the array of locations you get in that method - it will be the most recent.
I would advise checking the horizontalAccuracy of the locations before using them. Typically the first few location readings are really bad, and then slowly the readings settle down. The Horizontal accuracy reading is actually a radius giving the possible area of the reading. If you get 1 km, it means your location could be anywhere in a circle 1 km in radius. You probably want to discard readings that bad and wait for one that's within a few hundred meters (or better.)
Your viewDidLoad method is calling a method getDeparturesAtStop, and that method will likely be called before the first call to didUpdateLocations fires. (You don't show what that method does.)
Where is the code that is getting a zero lat/long?

not able to reliably update location ios 8

I've recently gotten into mobile programming. The code below is finicky; sometimes it works and sometimes it doesn't. I've tried suggestions I've found on here like restarting location services on the virtual iphone. It is not a info.plist issue: I have NSLocationWhenInUseUsageDescription set, and when I'm debugging I can see it has WhenInUse authorization. When I debug I get to the println statement in didFailWithError and it reads "The operation couldn’t be completed. (kCLErrorDomain error 0.)". I've put the code behind a button to try it out. Is the reliability of this a known issue? If I load the app onto a device will it go away? Any thoughts appreciated. Thanks.
EDIT
This is in ViewController.swift in a single view template application.
let manager = CLLocationManager()
#IBAction func getMyLocation (sender : AnyObject){
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
let status = CLLocationManager.authorizationStatus()
if status == CLAuthorizationStatus.NotDetermined
{
manager.requestWhenInUseAuthorization()
}
manager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
println("locations = \(locations)")
manager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!){
println(error)
manager.stopUpdatingLocation()
}
I download the the app developer kit from Apple, and when I run the app with this script on my iphone the location is reliably retrieved. Looks like it's just an iOS simulator issue.

Resources