Issues getting device/user location with iOS App, Swift - ios

Setup:
Xcode 7.3 (7D175)
Swift 2
Device is an iPad with iOS 9.3.1
I have a Swift class called LocationUtility, I am using it like so in a ViewController:
let locationUtil = LocationUtility()
locationUtil.initLocationManager()
The initLocationManager() function sets the CLLocationManager.delegate to my LocationUtility class:
func initLocationManager() {
seenError = false
locationFixAchieved = false
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.startUpdatingLocation()
}
}
The following delegate func is never being called:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
I have NSLocationAlwaysUsageDescription string set in my Info.plist
On my iPad, Privacy -> Location Services is Enabled.
My LocationUtility class is something a put together with, mostly code from other stackoverflow questions and answers about location functionality in Swift and iOS 8 and beyond. From my perspective I have all the right settings in my APP and on my device to be receiving location information.
Here is my complete LocationUtility class source code:
import UIKit
import Foundation
import CoreLocation
class LocationUtility: UIViewController, CLLocationManagerDelegate {
var locationStatus : NSString = "Not Started"
var locationManager: CLLocationManager!
var seenError : Bool = false
var locationFixAchieved : Bool = false
var currentLocation:CLLocation? = nil
func initLocationManager() {
seenError = false
locationFixAchieved = false
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled() {
//locationManager.delegate = self
//locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("LocationUtility -> didFailWithError()")
locationManager.stopUpdatingLocation()
if (seenError == false) {
seenError = true
print(error)
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("LocationUtility -> didUpdateLocations()")
if (locationFixAchieved == false) {
locationFixAchieved = true
//var locationArray = locations as NSArray
currentLocation = locations.last! as CLLocation
let coord = currentLocation!.coordinate
print("user current location")
print(coord.latitude)
print(coord.longitude)
}
}
// authorization status
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
print("LocationUtility -> didChangeAuthorizationStatus()!")
var shouldIAllow = false
switch status {
case CLAuthorizationStatus.Restricted:
locationStatus = "Restricted Access to location"
case CLAuthorizationStatus.Denied:
locationStatus = "User denied access to location"
case CLAuthorizationStatus.NotDetermined:
locationStatus = "Status not determined"
default:
locationStatus = "Allowed to location Access"
shouldIAllow = true
}
if (shouldIAllow == true) {
NSLog("Location to Allowed")
// Start location services
locationManager.startUpdatingLocation()
} else {
NSLog("Denied access: \(locationStatus)")
}
}
}

The symptoms you describe strongly suggest that your LocationUtility instance is getting deallocated, which deallocates the CLLocationManager and stops the entire process. It's not clear where you're instantiating LocationUtility but you need to make sure it's some place where the instance will remain "live" in memory while CLLocationManager does its things. If the view controller is deallocated, for example, then its instance vars will be deallocated, which looks like it probably includes your location manager.
Your question initially asked if the location manager had to be in the app delegate. It doesn't, of course, but it does have to be someplace that can prevent it from being deallocated while location updates are in progress.
If you're unsure when the LocationManager is getting deallocated, try implementing deinit on it and setting a breakpoint on that method.

Related

Location services permission alert disappears

I am asking for requestWhenInUseAuthorization from CLLocationManager and the user prompt displays but then quickly disappears.
According to other posts on SO it says that you have to declare your CLLocationManager var at the class level to fix this.
Problem is that I am already doing this and this still happens.
Any help would be appreciated.
class myLocation: CLLocationManagerDelegate {
var locationManager:CLLocationManager?
// Have also tried it as: let locationManager = CLLocationManager()
func start() {
if CLLocationManager.locationServicesEnabled() {
self.locationManager = CLLocationManager()
guard let manager = self.locationManager else {
print("Error creating Location Manager")
return
}
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
manager.requestWhenInUseAuthorization()
}
else {
print("Location Services Disabled")
}
}
//Delegate Methods
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .authorizedAlways, .authorizedWhenInUse:
manager.startUpdatingLocation()
default:
manager.requestWhenInUseAuthorization()
}
}
...
}
The key to fixing this was that the var I instantiated this class too was a local var. I moved that to a class var and it no longer disappears.
So for example:
class ViewController: UIViewController {
let location = myLocation.init()
override func viewDidLoad() {
super.viewDidLoad()
location.start()
}
}

Location Manager not updating location in swift. AlertView disappears

I want to get location inside a custom delegate in swift. Note that this worked perfectly 2 hours ago. The major problem is that the Location authorization alertView disappears by its own before I get to Allow it. So i tried to go within settings and allow it but it does not work. Why is the alertView disappearing by it self and why even though I allowed it through the settings I still cannot get an update? I added the correct key in the plist and also added the delegate and CoreLocation framework in the file. Also note that the didFail is not called at any point. Any advise would be appreciated
func getLocation(){
println("called")
let locationManager:CLLocationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
let status = CLLocationManager.authorizationStatus()
println(status.rawValue)
if(status != CLAuthorizationStatus.Authorized) {
locationManager.requestWhenInUseAuthorization()
println("called2")
}else{
locationManager.startUpdatingLocation()
println("allowed and updating")
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
println("updating")
var locationArray = locations as NSArray
var locationObj = locationArray.lastObject as CLLocation
println(locationObj)
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println(error)
}
func locationManager(manager: CLLocationManager!,
didChangeAuthorizationStatus status: CLAuthorizationStatus) {
var shouldIAllow = false
println(status)
switch status {
case CLAuthorizationStatus.Restricted:
println("Restricted Access to location")
case CLAuthorizationStatus.Denied:
println("User denied access to location")
case CLAuthorizationStatus.NotDetermined:
println("Status not determined")
default:
println("Allowed to location Access")
shouldIAllow = true
}
if (shouldIAllow == true) {
manager.startUpdatingLocation()
} else {
println("Denied access: \(status)")
}
}
Create a property from locationManager , because this way it is destroyed after you run your method. And don't forget to setup its delegate for example in viewDidLoad.

How to get Location user with CLLocationManager in swift?

I have this code on my view controller but this not working:
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
var location: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
location=CLLocationManager()
location.delegate = self
location.desiredAccuracy=kCLLocationAccuracyBest
location.startUpdatingLocation()
}
func locationManager(location:CLLocationManager, didUpdateLocations locations:AnyObject[]) {
println("locations = \(locations)")
label1.text = "success"
}
I have the permissions how I read in other post. but I don't obtain never, no println..
Thanks!!
first add this two line in plist file
1) NSLocationWhenInUseUsageDescription
2) NSLocationAlwaysUsageDescription
Then this is class working complete implement this
import UIKit
import CoreLocation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
var window: UIWindow?
var locationManager: CLLocationManager!
var seenError : Bool = false
var locationFixAchieved : Bool = false
var locationStatus : NSString = "Not Started"
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
initLocationManager();
return true
}
// Location Manager helper stuff
func initLocationManager() {
seenError = false
locationFixAchieved = false
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.locationServicesEnabled
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
}
// Location Manager Delegate stuff
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
locationManager.stopUpdatingLocation()
if (error) {
if (seenError == false) {
seenError = true
print(error)
}
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: AnyObject[]!) {
if (locationFixAchieved == false) {
locationFixAchieved = true
var locationArray = locations as NSArray
var locationObj = locationArray.lastObject as CLLocation
var coord = locationObj.coordinate
println(coord.latitude)
println(coord.longitude)
}
}
func locationManager(manager: CLLocationManager!,
didChangeAuthorizationStatus status: CLAuthorizationStatus) {
var shouldIAllow = false
switch status {
case CLAuthorizationStatus.Restricted:
locationStatus = "Restricted Access to location"
case CLAuthorizationStatus.Denied:
locationStatus = "User denied access to location"
case CLAuthorizationStatus.NotDetermined:
locationStatus = "Status not determined"
default:
locationStatus = "Allowed to location Access"
shouldIAllow = true
}
NSNotificationCenter.defaultCenter().postNotificationName("LabelHasbeenUpdated", object: nil)
if (shouldIAllow == true) {
NSLog("Location to Allowed")
// Start location services
locationManager.startUpdatingLocation()
} else {
NSLog("Denied access: \(locationStatus)")
}
}
}
Following are the simple steps for getting user location in Swift 3
1) First add this line in plist file with description
NSLocationWhenInUseUsageDescription
2) Add CoreLocation.framework in your project(Under section Build Phases-> Link Binary With Library)
3) In AppDelegate class
import CoreLocation
4) Create locationManager Object as follows
var locationManager:CLLocationManager!
5) Write following code in didFinishLaunchingWithOptions
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 200
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
6) Confirm CLLocationManagerDelegate delegate like as follows
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate
7) Write CLLocationManagerDelegate delegate method for getting user location
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("location error is = \(error.localizedDescription)")
}
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = (manager.location?.coordinate)!
print("Current Locations = \(locValue.latitude) \(locValue.longitude)")
}
Since you're declaring location as an explicitly unwrapped optional (CLLocationManager!) it requires an initializer, either in an init method as suggested by jhurray, or just inline, as:
var location: CLLocationManager! = nil
Note that you've got other possible problems as well, including that iOS 8 has new requirements for querying the user for permission to use CoreLocation. See this question for more information.
This is the same code as above but cleaned up to work with Swift as of the date of this posting. This worked for me.
Kudos to the original poster.
(note, stick this into whatever class you will use to handle your location stuff.)
var lastLocation = CLLocation()
var locationAuthorizationStatus:CLAuthorizationStatus!
var window: UIWindow?
var locationManager: CLLocationManager!
var seenError : Bool = false
var locationFixAchieved : Bool = false
var locationStatus : NSString = "Not Started"
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.initLocationManager()
}
// Location Manager helper stuff
func initLocationManager() {
seenError = false
locationFixAchieved = false
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
}
// Location Manager Delegate stuff
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
locationManager.stopUpdatingLocation()
if ((error) != nil) {
if (seenError == false) {
seenError = true
print(error)
}
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
if (locationFixAchieved == false) {
locationFixAchieved = true
var locationArray = locations as NSArray
var locationObj = locationArray.lastObject as CLLocation
var coord = locationObj.coordinate
println(coord.latitude)
println(coord.longitude)
}
}
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
var shouldIAllow = false
switch status {
case CLAuthorizationStatus.Restricted:
locationStatus = "Restricted Access to location"
case CLAuthorizationStatus.Denied:
locationStatus = "User denied access to location"
case CLAuthorizationStatus.NotDetermined:
locationStatus = "Status not determined"
default:
locationStatus = "Allowed to location Access"
shouldIAllow = true
}
NSNotificationCenter.defaultCenter().postNotificationName("LabelHasbeenUpdated", object: nil)
if (shouldIAllow == true) {
NSLog("Location to Allowed")
// Start location services
locationManager.startUpdatingLocation()
} else {
NSLog("Denied access: \(locationStatus)")
}
}
Do following stuff in viewcontroller [Using swift] -
class ViewController:
UIViewController,MKMapViewDelegate,CLLocationManagerDelegate {
var locationManager: CLLocationManager?
var usersCurrentLocation:CLLocationCoordinate2D?
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager = CLLocationManager()
if CLLocationManager.authorizationStatus() == .NotDetermined{
locationManager?.requestAlwaysAuthorization()
}
locationManager?.desiredAccuracy = kCLLocationAccuracyBest
locationManager?.distanceFilter = 200
locationManager?.delegate = self
startUpdatingLocation()
usersCurrentLocation = CLLocationCoordinate2DMake(LATTITUDE, LONGITUDE)
let span = MKCoordinateSpanMake(0.005, 0.005)
let region = MKCoordinateRegionMake(usersCurrentLocation!, span)
mapview.setRegion(region, animated: true)
mapview.delegate = self
mapview.showsUserLocation = true
}
//MARK: CLLocationManagerDelegate methods
func startUpdatingLocation() {
self.locationManager?.startUpdatingLocation()
}
func stopUpdatingLocation() {
self.locationManager?.stopUpdatingLocation()
}
// MARK: MKMapViewDelegate
func mapView(mapView: MKMapView, didUpdateUserLocation userLocation: MKUserLocation){
mapview.centerCoordinate = userLocation.location!.coordinate
mapview.showsUserLocation = true
regionWithGeofencing()
}
You need to have init functions.
Override init(coder:) and init(nibName: bundle:) and add any custom init you want.
Because you have said that location is not optional, you must initialize it before your super init calls in ALL of your init functions.
func init() {
...
location = CLLocationManager()
// either set delegate and other stuff here or in viewDidLoad
super.init(nibName:nil, bundle:nil)
// other initialization below
}
It should be written as
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

CLLocation Manager in Swift to get Location of User

I am trying to convert an old app in ObjC to Swift as a practice exercise and have ran in to some issues. The way I had it in the old app, it was establishing the CLLocation Manager and then I would use:
manager = [[CLLocationManager alloc]init];
manager.delegate = self;
manager.desiredAccuracy = kCLLocationAccuracyBest;
[manager startUpdatingLocation]
which would call automatically:
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
}
and from there I could extract all the information I needed. But in swift, there is no autocompletion of this method and I cannot figure out how to reproduce it. The documentation says that
startUpdatingLocation()
will still be called by the delegate, but it isn't happening.
This is what I have so far:
import UIKit
import corelocation
class ViewController: UIViewController,CLLocationManagerDelegate{
#IBOutlet var gpsResult : UILabel
var manager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.startUpdatingLocation()
}
func locationManager(manager:CLLocationManager, didUpdateLocations locations:AnyObject[]) {
println("locations = \(locations)")
gpsResult.text = "success"
}
}
Any help or pointers on where to look would be appreciated. Thanks.
EDIT: Updated from Suggestions, but still not working
EDIT2: Seems to be some bug not allowing the method to work properly in the ViewController
You are missing two things. First, you have to ask for permission using requestAlwaysAuthorization or requestWhenInUseAuthorization(). So your viewDidLoad() should be like this:
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
Second, edit your Info.plist as indicated here.
First add this two line in plist file
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
Then this is class working complete implement this
import UIKit
import CoreLocation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
var window: UIWindow?
var locationManager: CLLocationManager!
var seenError : Bool = false
var locationFixAchieved : Bool = false
var locationStatus : NSString = "Not Started"
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
initLocationManager();
return true
}
// Location Manager helper stuff
func initLocationManager() {
seenError = false
locationFixAchieved = false
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.locationServicesEnabled
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
}
// Location Manager Delegate stuff
// If failed
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
locationManager.stopUpdatingLocation()
if (error) {
if (seenError == false) {
seenError = true
print(error)
}
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: AnyObject[]!) {
if (locationFixAchieved == false) {
locationFixAchieved = true
var locationArray = locations as NSArray
var locationObj = locationArray.lastObject as CLLocation
var coord = locationObj.coordinate
println(coord.latitude)
println(coord.longitude)
}
}
// authorization status
func locationManager(manager: CLLocationManager!,
didChangeAuthorizationStatus status: CLAuthorizationStatus) {
var shouldIAllow = false
switch status {
case CLAuthorizationStatus.Restricted:
locationStatus = "Restricted Access to location"
case CLAuthorizationStatus.Denied:
locationStatus = "User denied access to location"
case CLAuthorizationStatus.NotDetermined:
locationStatus = "Status not determined"
default:
locationStatus = "Allowed to location Access"
shouldIAllow = true
}
NSNotificationCenter.defaultCenter().postNotificationName("LabelHasbeenUpdated", object: nil)
if (shouldIAllow == true) {
NSLog("Location to Allowed")
// Start location services
locationManager.startUpdatingLocation()
} else {
NSLog("Denied access: \(locationStatus)")
}
}
}
I'm not sure why, but it seems like startUpdatingLocation isn't presenting the user prompt on the iOS 7 simulator, but when I enabled it manually it worked as expected if I used the newer form of the delegate method:
var manager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.startUpdatingLocation()
}
func locationManager(manager:CLLocationManager, didUpdateLocations locations:[AnyObject]) { // Updated to current array syntax [AnyObject] rather than AnyObject[]
println("locations = \(locations)")
}
The format you're using has been deprecated since iOS 5 or 6, so apparently it's not supported at all by the swift bridging layers.
had the same issue. didUpdateLocations - was not working. Run your app. Go to the Settings page -> Privacy -> Location and turn off Location Services. didFailWithError will catch the error about absent Location Services. Then turn it on. Since that moment didUpdateLocations will catch locations.
Here is my very simple code that works:
first add Core Location framework in General/Linked Frameworks and Libraries
then add following into Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>blablabla</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>blablabla</string>
this is my ViewController.swift file:
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
var locationManager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(manager:CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("locations = \(locations)")
}
}
For Swift 3
import UIKit
import CoreLocation
class ViewController: UIViewController,CLLocationManagerDelegate {
var locationManager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(_ manager:CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("locations = \(locations)")
}
}
I hope there are two ways.
var locationManager: CLLocationManager = CLLocationManager()
var initialLocation :CLLocation?
var updatedUserLocation :CLLocation?
override func viewDidLoad() {
super.viewDidLoad() {
//MapView Location
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
locationManager.startUpdatingHeading()
}
Implementing CLLocationManagerDelegate :
//CLLocationManager Delegate
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// This only works when user location is updated.
gpsProviderStatusLabel.changeStatusToOn(gpsProviderStatusLabel)
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
//Error indicates GPS permission restricted
gpsProviderStatusLabel.changeStatusToOff(gpsProviderStatusLabel)
//Initial Location
initialLocation = locations.first
//Getting Updated Location
updatedUserLocation = locations.last
}
Checking CLLocationDelegate Authorization:
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
//This method does real time status monitoring.
switch status {
case .NotDetermined:
print(".NotDetermined")
break
case .AuthorizedAlways:
print(".AuthorizedAlways")
gpsProviderStatusLabel.changeStatusToOn(gpsProviderStatusLabel)
break
case .Denied:
print(".Denied")
gpsProviderStatusLabel.changeStatusToOff(gpsProviderStatusLabel)
break
case .AuthorizedWhenInUse:
print(".AuthorizedWhenInUse")
gpsProviderStatusLabel.changeStatusToOn(gpsProviderStatusLabel)
break
case .Restricted:
print(".Restricted")
break
default:
print("Unhandled authorization status")
break
}
}
Note: changeStatusToOn or changeStatusToOff is a UILabel Extenion method which makes the Label text On/Off with Green/Red Colors.
don't forget to add
NSLocationWhenInUseUsageDescription or
NSLocationAlwaysUsageDescription
in your configuration file (target/Info/custom iOS target properties
Add bellow 2 property in info.plist
NSLocationWhenInUseUsageDescription : Location information is used for fraud prevention
Privacy - Location Usage Description : Location information is used for fraud prevention
If you want to get the user location updated by default, without clicking 'Simulate location' everytime, go to
YourProject-->Build Phases-->Link Binary with libraries-->Add corelocation.framework
The location gets updated automatically/by default when you run the app in the simulator. Tested and works in Swift 2 !
This will ask for permission and track if given permission else quit with an alert. Stops tracking on back button press.
info.plist
<key>NSLocationAlwaysUsageDescription</key>
<string>Allow tracking while completing a survey</string>
Class:
import UIKit
import CoreLocation
class LocationViewController: BaseViewController, CLLocationManagerDelegate {
// MARK: Constants
private static let enableLocationServices = [
"title" : "Location",
"message" : "Enable location services",
"buttonTitle" : "OK"
]
// MARK: Private variables
private var manager: CLLocationManager?
// MARK: UIViewCOntroller methods
#IBAction func backButtonPressed(sender : UIButton) {
stopTracking()
detatchLocationManager()
dismissViewControllerAnimated(true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
attachLocationManager()
}
// Mark: Location
func locationManager(manager: CLLocationManager,
didChangeAuthorizationStatus status: CLAuthorizationStatus)
{
if status == .AuthorizedAlways {
manager.startUpdatingLocation()
} else if status != .NotDetermined {
showEnableLocationServicesAlert()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
for location in locations {
getDependencyService().getProject().appendLocationTrackingFile(location.timestamp, latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
}
}
// MARK: LocationViewController
private func attachLocationManager() {
manager = CLLocationManager()
manager?.delegate = self
manager?.desiredAccuracy = kCLLocationAccuracyBest
if CLLocationManager.authorizationStatus() != .AuthorizedAlways {
manager?.requestAlwaysAuthorization()
} else if CLLocationManager.locationServicesEnabled() {
startTracking()
}
}
private func detatchLocationManager() {
manager?.stopUpdatingLocation()
manager?.delegate = nil
manager = nil
}
private func startTracking() {
manager?.startUpdatingLocation()
}
private func stopTracking() {
manager?.stopUpdatingLocation()
}
private func showEnableLocationServicesAlert() {
getDependencyService().getUiHelper().showAlert(FrogFirstSurveyViewController.enableLocationServices, completion: {
self.dismissViewControllerAnimated(true, completion: nil)
})
}
}
Swift:
Add following in
import CoreLocation
class YourViewController: UIViewController
{
var locationManager:CLLocationManager!
}
//MARK:- Location Manager
extension YourViewController: CLLocationManagerDelegate {
func stratLocationManager()
{
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.checkUsersLocationServicesAuthorization()
locationManager.startUpdatingLocation()
}
func checkUsersLocationServicesAuthorization(){
/// Check if user has authorized Total Plus to use Location Services
if CLLocationManager.locationServicesEnabled()
{
switch CLLocationManager.authorizationStatus()
{
case .notDetermined:
// Request when-in-use authorization initially
// This is the first and the ONLY time you will be able to ask the user for permission
self.locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
break
case .restricted, .denied:
// Disable location features
PrintLogs("Location Access Not Available")
break
case .authorizedWhenInUse, .authorizedAlways:
// Enable features that require location services here.
PrintLogs("Location Access Available")
break
}
}
}
func locationManager(_ manager:CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("locations = \(locations)")
}
}
Just call the init(vc : UIViewController).
import Foundation
import CoreLocation
import UIKit
class LocManager : NSObject{
var permission : ((Bool?)->())?
private var locationManager : CLLocationManager!
init(_ vc : UIViewController) {
super.init()
self.locationManager = CLLocationManager()
self.locationManager.delegate = vc as? CLLocationManagerDelegate
setUpLocationManagerDelegate()
}
}
extension LocManager : CLLocationManagerDelegate {
fileprivate func setUpLocationManagerDelegate(){
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let lat = locations.last?.coordinate.latitude, let long = locations.last?.coordinate.longitude{
print("\n\nThe current Lat/Long Is Here\n\n")
let coordinates = CLLocationCoordinate2D(latitude: lat, longitude: long)
}else{
print("Unable To Access Locaion")
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .authorizedAlways,.authorizedWhenInUse:
print("Good to go and use location")
locationManager.startUpdatingLocation()
self.callPermisssionCompletion(val: true)
case .denied:
print("DENIED to go and use location")
self.callPermisssionCompletion(val: false)
case .restricted:
print("DENIED to go and use location")
self.callPermisssionCompletion(val: nil)
case .notDetermined:
print("DENIED to go and use location")
self.callPermisssionCompletion(val: nil)
default:
print("Unable to read location :\(status)")
}
}
fileprivate func callPermisssionCompletion(val : Bool?){
guard let comp = self.permission else {
print("\n\n Unable to locate completions \n\n")
return
}
if let val = val{
comp(val)
}
}
}

Implement CLLocationManagerDelegate methods in Swift

I've been trying to get this to work for awhile now, and I've come here to ask- how do I go about with using the CLLocationManagerDelegate methods in Swift? I've put this at the top of my class:
var locationManager = CLLocationManager()
I've put the following into my viewDidLoad method:
locationManager.delegate = self
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
And I've tried using these delegate methods with no avail:
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: AnyObject[]!) {
locationReceived = true
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
locationReceived = false
}
I've also tried using #optional in front of the functions, but Xcode then throws a compiler error. Any ideas?
You need to add the NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key to your plist if you haven't already, they are now mandatory,
iOS8+ requires one of these two strings to be set to use locations. Which one you use depends on how you intend ask for the location.
Use NSLocationAlwaysUsageDescription for apps that want to use the device's location even when the app is not open and being used.
Use NSLocationWhenInUseUsageDescription for apps that want to use the device's location only when the app is open and in use.
Note: When you add the strings, before you build and run, delete the app off your device and let it do a fresh install. It seems that if the app was authorized to use locations before you upgraded to iOS8 it doesn’t ask for your permission again and doesn’t see that you set those strings. Doing a delete and clean install solves this.
Setting either of the strings prompts a pop up on install/first use along the lines of: "Allow "ThisApp" to access your location even when you are not using the App"
Here's a Screenshot of the plist file.
First add this two line in plist file
1) NSLocationWhenInUseUsageDescription
2) NSLocationAlwaysUsageDescription
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate
var seenError : Bool = false
var locationFixAchieved : Bool = false
var locationStatus : NSString = "Not Started"
var locationManager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
}
func initLocationManager() {
seenError = false
locationFixAchieved = false
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.locationServicesEnabled
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
locationManager.stopUpdatingLocation()
if (error) {
if (seenError == false) {
seenError = true
print(error)
}
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: AnyObject[]!) {
if (locationFixAchieved == false) {
locationFixAchieved = true
var locationArray = locations as NSArray
var locationObj = locationArray.lastObject as CLLocation
var coord = locationObj.coordinate
println(coord.latitude)
println(coord.longitude)
}
}
func locationManager(manager: CLLocationManager!,
didChangeAuthorizationStatus status: CLAuthorizationStatus) {
var shouldIAllow = false
switch status {
case CLAuthorizationStatus.Restricted:
locationStatus = "Restricted Access to location"
case CLAuthorizationStatus.Denied:
locationStatus = "User denied access to location"
case CLAuthorizationStatus.NotDetermined:
locationStatus = "Status not determined"
default:
locationStatus = "Allowed to location Access"
shouldIAllow = true
}
NSNotificationCenter.defaultCenter().postNotificationName("LabelHasbeenUpdated", object: nil)
if (shouldIAllow == true) {
NSLog("Location to Allowed")
// Start location services
locationManager.startUpdatingLocation()
} else {
NSLog("Denied access: \(locationStatus)")
}
}
To get User Current Location :-
Step 1: let locationManager = CLLocationManager() // make object of CLLocationManager class.
Step 2: In viewDidLoad instantiate the CLLocationManager class like,
// For use in background
self.locationManager.requestAlwaysAuthorization()
// For use in foreground
self.locationManager.requestWhenInUseAuthorization()
if (CLLocationManager.locationServicesEnabled())
{
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
Step 3: Now implement the delegate methods of CLLocationManager
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
var locValue:CLLocationCoordinate2D = manager.location.coordinate
println("locations = \(locValue.latitude) \(locValue.longitude)")
}
Step 4:
Don't forget to add NSLocationAlwaysUsageDescription in the Info.plist as in iOS 8 it is mandatory to add this. This will ask permission to use user's location.
I had the same issue. didUpdateLocations - was not working. Run your app.
Go to the Settings page -> Privacy -> Location and turn off Location Services. didFailWithError will catch the error about absent Location Services. Then turn it on. Since that moment didUpdateLocations will catch locations.
This is a bit of an old thread, yet none of the above worked for me on Swift 2.2 xCode 7.3.1.
The problem is I was using:
func locationManager(manager: CLLocationManager!, didUpdateLocation locations: [AnyObject]!) {
print("Got location")
locationManager.stopUpdatingLocation()
}
And this never got called. When I changed to:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("Got location")
locationManager.stopUpdatingLocation()
}
It all worked out. Seems like the delegate is not called when using [AnyObject]

Resources