Declaration is only valid at file scope how to fix? - ios

I have a Problem in my swift file.
Im trying to follow a tutorial on Youtube and he doesn't get the error.
Here is the code:
class ViewController: UIViewController, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
private var currentLocation: CLLocationCoordinate2D?
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
configerLocationServices()
}
private func configerLocationServices() {
locationManager.delegate = self
let status = CLLocationManager.authorizationStatus()
if status == .notDetermined {
locationManager.requestWhenInUseAuthorization()
} else if status == .authorizedAlways || status == .authorizedWhenInUse {
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
}
extension ViewController: CLLocationManagerDelegate { //Error: Declaration is only valid at file scope
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("Did get latest Lcation")
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
print("The Status changed")
}
}
}
I don't know what im doing wrong, has anyone a solution?
Thank you in advance.

Thats because you have declared an extension inside your class. Move it outside the class and compiler will stop complaining
class ViewController: UIViewController {
private let locationManager = CLLocationManager()
private var currentLocation: CLLocationCoordinate2D?
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
configerLocationServices()
}
private func configerLocationServices() {
locationManager.delegate = self
let status = CLLocationManager.authorizationStatus()
if status == .notDetermined {
locationManager.requestWhenInUseAuthorization()
} else if status == .authorizedAlways || status == .authorizedWhenInUse {
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("Did get latest Lcation")
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
print("The Status changed")
}
}
You have clearly confirmed to CLLocationManagerDelegate in your ViewController extension so you dont need to confirm it in class declaration (this will result in compiler giving you a warning that duplicate confirmation to protocol) so change class ViewController: UIViewController, CLLocationManagerDelegate to class ViewController: UIViewController

Remove CLLocationManagerDelegate declaration in class ViewController: UIViewController, CLLocationManagerDelegate line. Also, make sure that you set all pairs of curly braces correctly, I mean open and close in proper places

Related

How to track set locationManager.delegate the right way?

I tried to use CoreLocation with Swift to track the user's location:
(Below you can find the code of may ViewController.swift file.)
But the code doesn't seems working as I've expected, because I'm still getting the same error every-time I'm launching the application:
I'm sure this is the problem why I'm not able to get a result from the locationManager() function that should print out the current location.
It says "Cannot assign value of type 'ViewController' to type 'CLLocationManagerDelegate?'"
import UIKit
import CoreLocation
class ViewController: UIViewController, WKUIDelegate {
override func viewDidLoad() {
super.viewDidLoad()
if CLLocationManager.locationServicesEnabled() {
print("CLLocationManager is available")
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
locationManager.delegate = self
locationManager.startUpdatingLocation()
}
}
let locationManager = CLLocationManager()
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
print(location.coordinate)
}
}
}
Does anyone now how to fix this problem? - Any help would be very appreciated, thanks a million in advance.
You simply need to declare conformance to CLLocationManagerDelegate. You can either do this directly in the class declaration just as you did with WKUIDelegate or in an extension of ViewController.
class ViewController: UIViewController, WKUIDelegate, CLLocationManagerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
if CLLocationManager.locationServicesEnabled() {
print("CLLocationManager is available")
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
locationManager.delegate = self
locationManager.startUpdatingLocation()
}
}
let locationManager = CLLocationManager()
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
print(location.coordinate)
}
}
}
With extension:
class ViewController: UIViewController, WKUIDelegate {
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
if CLLocationManager.locationServicesEnabled() {
print("CLLocationManager is available")
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
locationManager.delegate = self
locationManager.startUpdatingLocation()
}
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
print(location.coordinate)
}
}
}

LocationManager singleton didUpdateLocations not getting called

I have created a singleton LocationManager class to handle location updates in my application. In the first view controller the shared instance is accessed in viewDidLoad and a call to getCurrentLocation is made. "Getting users location..." prints to the console however the delegate method didUpdateLocations on the location manager is never called and the location is not updated. I have the required keys in the info.plist and the expected permissions prompts show.
I have a feeling this is a threading issue with the LocationManager falling out of scope but I'm not sure, would be great if someone could point me in the right direction !
Location Manager:
import Foundation
import CoreLocation
class LocationManager: NSObject, CLLocationManagerDelegate {
static let shared = LocationManager()
var manager: CLLocationManager!
override init() {
super.init()
self.manager = CLLocationManager()
self.manager.delegate = self
if CLLocationManager.authorizationStatus() == .notDetermined {
self.manager.requestWhenInUseAuthorization()
}
self.manager.desiredAccuracy = kCLLocationAccuracyBest
}
public func getCurrentLocation(){
print("Getting users location...")
self.manager.startUpdatingLocation()
}
func locationManager(manager:CLLocationManager, didUpdateLocations locations:[AnyObject]) {
self.manager.stopUpdatingLocation()
print("locations = \(locations)")
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error.localizedDescription)
}}
ViewController:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var savedAreasTableView: UITableView!
#IBOutlet weak var noSavedAreasLabel: UILabel!
var manager: LocationManager! = LocationManager.shared
override func viewDidLoad() {
super.viewDidLoad()
self.noSavedAreasLabel.text = "You have no saved areas available !\nTo add some, search for a location and then favourite it."
//Check here to see if user has any favourited areas
self.savedAreasTableView.isHidden = true
self.noSavedAreasLabel.isHidden = false
self.manager.getCurrentLocation()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The correct delegate function is this:
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation])

How to fetch current location when users move in swift [duplicate]

I want to get the current longitude and latitude of a location using Swift and display them via labels. I tried to do this but nothing displays on the labels.
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate{
#IBOutlet weak var longitude: UILabel!
#IBOutlet weak var latitude: UILabel!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
if (CLLocationManager.locationServicesEnabled()) {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
} else {
println("Location services are not enabled");
}
}
// MARK: - CoreLocation Delegate Methods
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
locationManager.stopUpdatingLocation()
removeLoadingView()
if (error) != nil {
print(error)
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
var locationArray = locations as NSArray
var locationObj = locationArray.lastObject as CLLocation
var coord = locationObj.coordinate
longitude.text = coord.longitude
latitude.text = coord.latitude
longitude.text = "\(coord.longitude)"
latitude.text = "\(coord.latitude)"
}
}
IMHO, you are over complicating your code when the solution you are looking is pretty simple.
I have done it by using the following code:
First create an instance of CLLocationManager and Request Authorization
var locManager = CLLocationManager()
locManager.requestWhenInUseAuthorization()
then check if the user allowed authorization.
var currentLocation: CLLocation!
if
CLLocationManager.authorizationStatus() == .authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == .authorizedAlways
{
currentLocation = locManager.location
}
to use it just do this
label1.text = "\(currentLocation.coordinate.longitude)"
label2.text = "\(currentLocation.coordinate.latitude)"
Your idea of setting them to the label.text is correct, however the only reason I can think of is that the user is not giving you permission and that is why your current Location data will be nil.
However you would need to debug and tell us that.
Also the CLLocationManagerDelegate is not necessary.
Hopefully this helps. Ask away if you have doubts.
For Swift 3:
First you need to set allowance to receive User's GPS in the info.plist.
Set: NSLocationWhenInUseUsageDescription with a random String.
And/or: NSLocationAlwaysUsageDescription with a random String.
Then:
import UIKit
import MapKit
class ViewController: UIViewController {
var locManager = CLLocationManager()
var currentLocation: CLLocation!
override func viewDidLoad() {
super.viewDidLoad()
locManager.requestWhenInUseAuthorization()
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways){
guard let currentLocation = locManager.location else {
return
}
print(currentLocation.coordinate.latitude)
print(currentLocation.coordinate.longitude)
}
}
}
Done.
Despite other advice you should use the CLLocationManagerDelegate to safely retrieve a location (without using it you may get null locations when the location manager doesn't have enough time to update). I strongly recommend wrapping the location manager code within a static shared helper (something along these lines):
class Locator: NSObject, CLLocationManagerDelegate {
enum Result <T> {
case .Success(T)
case .Failure(ErrorType)
}
static let shared: Locator = Locator()
typealias Callback = (Result <Locator>) -> Void
var requests: Array <Callback> = Array <Callback>()
var location: CLLocation? { return sharedLocationManager.location }
lazy var sharedLocationManager: CLLocationManager = {
let newLocationmanager = CLLocationManager()
newLocationmanager.delegate = self
// ...
return newLocationmanager
}()
// MARK: - Authorization
class func authorize() { shared.authorize() }
func authorize() { sharedLocationManager.requestWhenInUseAuthorization() }
// MARK: - Helpers
func locate(callback: Callback) {
self.requests.append(callback)
sharedLocationManager.startUpdatingLocation()
}
func reset() {
self.requests = Array <Callback>()
sharedLocationManager.stopUpdatingLocation()
}
// MARK: - Delegate
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
for request in self.requests { request(.Failure(error)) }
self.reset()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: Array <CLLocation>) {
for request in self.requests { request(.Success(self)) }
self.reset()
}
}
Then in view did load (or anywhere else you need to get the current location) run:
Locator.shared.locate { result in
switch result {
case .Success(locator):
if let location = locator.location { /* ... */ }
case .Failure(error):
/* ... */
}
}
In Swift
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
//Labels outlets
#IBOutlet var localityTxtField: UITextField!
#IBOutlet var postalCodeTxtField: UITextField!
#IBOutlet var aAreaTxtField: UITextField!
#IBOutlet var countryTxtField: UITextField!
let locationManager = CLLocationManager()
//View Didload
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
//Button Location
#IBAction func findMyLocation(_ sender: AnyObject) {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)->Void in
if (error != nil) {
print("Reverse geocoder failed with error" + (error?.localizedDescription)!)
return
}
if (placemarks?.count)! > 0 {
print("placemarks",placemarks!)
let pm = placemarks?[0]
self.displayLocationInfo(pm)
} else {
print("Problem with the data received from geocoder")
}
})
}
func displayLocationInfo(_ placemark: CLPlacemark?) {
if let containsPlacemark = placemark {
print("your location is:-",containsPlacemark)
//stop updating location to save battery life
locationManager.stopUpdatingLocation()
let locality = (containsPlacemark.locality != nil) ? containsPlacemark.locality : ""
let postalCode = (containsPlacemark.postalCode != nil) ? containsPlacemark.postalCode : ""
let administrativeArea = (containsPlacemark.administrativeArea != nil) ? containsPlacemark.administrativeArea : ""
let country = (containsPlacemark.country != nil) ? containsPlacemark.country : ""
localityTxtField.text = locality
postalCodeTxtField.text = postalCode
aAreaTxtField.text = administrativeArea
countryTxtField.text = country
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error while updating location " + error.localizedDescription)
}
}
In current thread a solution was proposed without delegate but in Xcode 9.1 testing in simulator it did not work, location was nil. This code worked:
import UIKit
import MapKit
class ViewController: UIViewController, CLLocationManagerDelegate {
var locationManager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
if (CLLocationManager.locationServicesEnabled())
{
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last! as CLLocation
/* you can use these values*/
let lat = location.coordinate.latitude
let long = location.coordinate.longitude
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I am junior but I solved it in this way:
I have created extension of my class inherited CLLocationManagerDelegate and following steps:
1.Import CoreLocation to your ViewController
import CoreLocation
2.Then initialize location manager and location variables inside your ViewController.
var locManager = CLLocationManager()
var currentUserLocation: CLLocation!
Inside viewDidLoad() request location init delegate and requestUsageDescription
locManager.requestWhenInUseAuthorization()
locManager.delegate = self
locManager.requestLocation()
Then I have just created extension for my viewController inheriting CLLocationManagerDelegate
extension theNameOfYourViewController: CLLocationManagerDelegate{
func locationManager(_ manager: CLLocationManager, didFailWithError error: Swift.Error) {
print(error)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// .requestLocation will only pass one location to the locations array
// hence we can access it by taking the first element of the array
if let location = locations.first {
print(location.coordinate.latitude)
print(location.coordinate.longitude)
}
}
}
Just remember to change the names according your needs also whenever you need location just use the function request location
locManager.requestLocation()
I agree with Kevin above, but if you're looking for less code for something simpler the following will suffice:
Make sure to use the CLLocationManagerDelegate
Swift 4:
In viewDidLoad you can add the following
locationManager.requestWhenInUseAuthorization()
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse) || (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways) {
currentLocation = locationManager.location
print(currentLocation.coordinate.latitude)
print(currentLocation.coordinate.longitude)
}
}
And for the first request respond once the user gives or denies permission:
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
locationManager.requestLocation()
currentLocation = locationManager.location
print(currentLocation.coordinate.latitude)
print(currentLocation.coordinate.longitude)
//Process location information and update.
}
Make sure to add the following keys to Info.plist:
Privacy - Location When In Use Usage Description
Privacy - Location Always and When In Use Usage Description
Create User class:
import Foundation
import CoreLocation
import MapKit
class User: NSObject, ObservableObject {
#Published var position = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
let manager = CLLocationManager()
override init() {
super.init()
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.requestLocation()
}
}
extension User: CLLocationManagerDelegate {
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
print("Location services authorization request")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("User location updated")
print("Updated position: \(locations.first?.coordinate.latitude ?? 00)")
if let location = locations.first {
self.position = location.coordinate
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Failed to find user's location: \(error.localizedDescription)")
}
}
Update
Swift 5+
Xcode 13+
Add these permission in info plist
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs your location to show nearby services</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs your location to show nearby services</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs your location to show nearby services</string>
Import this in your view controller
import CoreLocation
in viewDidLoad()
override func viewDidLoad() {
locationManager.requestWhenInUseAuthorization()
locationManager.requestLocation()
}
Create extension like this
extension RegisterViewController : CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("error:: \(error.localizedDescription)")
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
locationManager.requestLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let locationSafe = locations.last {
locationManager.stopUpdatingLocation()
let latitude = locationSafe.coordinate.latitude
let longitude = locationSafe.coordinate.longitude
self.currentLatitude = latitude
self.currentLongitude = longitude
print(" Lat \(latitude) , Longitude \(longitude)")
}
if locations.first != nil {
print("location:: \(locations[0])")
}
}
}
Run and check this

Shared instance of CLLocationManager

I was trying to create simple shared instance of CLLocationManager for my app.
There was no problem creating shared instance:
import UIKit
import CoreLocation
protocol LocationHandlerDelegate: class {
func locationHandlerDidUpdateLocation(location: CLLocation?)
func locationHandlerDidFailWithError(error: NSError)
}
class LocationHandler: NSObject, CLLocationManagerDelegate {
var locationManager: CLLocationManager!
var location: CLLocation?
weak var delegate: LocationHandlerDelegate?
static let sharedInstance = LocationHandler()
override init() {
super.init()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
if CLLocationManager.authorizationStatus() == .NotDetermined {
locationManager.requestWhenInUseAuthorization()
}
}
// MARK: -
// MARK: - CLLocationManagerDelegate functions
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
delegate?.locationHandlerDidUpdateLocation(locations.last)
self.location = locations.last
locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
delegate?.locationHandlerDidFailWithError(error)
locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .AuthorizedAlways || status == .AuthorizedWhenInUse {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
}
}
}
But for some reason when I call my shared instance from another class:
class TodayViewController: UIViewController, CLLocationManagerDelegate, LocationHandlerDelegate {
super.viewDidLoad() {
LocationHandler.sharedInstance.delegate = self
if #available(iOS 9.0, *) {
LocationHandler.sharedInstance.locationManager.requestLocation()
} else {
LocationHandler.sharedInstance.locationManager.startUpdatingLocation()
}
}
...
// MARK: - LocationHandlerDelegate function
func locationHandlerDidUpdateLocation(location: CLLocation?) {
if let location = location {
print("Current lcoation: \(location)")
}
else {
// ...
}
}
func locationHandlerDidFailWithError(error: NSError) {
print("Error finding lcoation: \(error.localizedDescription)")
}
}
None of CLLocationManagerDelegate functions in my LocationHandler are called.
But if in TodayViewController I write
LocationHandler.sharedInstance.locationManager.delegate = self
instead of
LocationHandler.sharedInstance.delegate = self
and I implement CLLocationManagerDelegate functions in my TodayViewController instead of LocationHandler then those delegate functions are called. So I guess there may be some problem with instancing? Or am I missing something else?

How to get current longitude and latitude using CLLocationManager-Swift

I want to get the current longitude and latitude of a location using Swift and display them via labels. I tried to do this but nothing displays on the labels.
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate{
#IBOutlet weak var longitude: UILabel!
#IBOutlet weak var latitude: UILabel!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
if (CLLocationManager.locationServicesEnabled()) {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
} else {
println("Location services are not enabled");
}
}
// MARK: - CoreLocation Delegate Methods
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
locationManager.stopUpdatingLocation()
removeLoadingView()
if (error) != nil {
print(error)
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
var locationArray = locations as NSArray
var locationObj = locationArray.lastObject as CLLocation
var coord = locationObj.coordinate
longitude.text = coord.longitude
latitude.text = coord.latitude
longitude.text = "\(coord.longitude)"
latitude.text = "\(coord.latitude)"
}
}
IMHO, you are over complicating your code when the solution you are looking is pretty simple.
I have done it by using the following code:
First create an instance of CLLocationManager and Request Authorization
var locManager = CLLocationManager()
locManager.requestWhenInUseAuthorization()
then check if the user allowed authorization.
var currentLocation: CLLocation!
if
CLLocationManager.authorizationStatus() == .authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == .authorizedAlways
{
currentLocation = locManager.location
}
to use it just do this
label1.text = "\(currentLocation.coordinate.longitude)"
label2.text = "\(currentLocation.coordinate.latitude)"
Your idea of setting them to the label.text is correct, however the only reason I can think of is that the user is not giving you permission and that is why your current Location data will be nil.
However you would need to debug and tell us that.
Also the CLLocationManagerDelegate is not necessary.
Hopefully this helps. Ask away if you have doubts.
For Swift 3:
First you need to set allowance to receive User's GPS in the info.plist.
Set: NSLocationWhenInUseUsageDescription with a random String.
And/or: NSLocationAlwaysUsageDescription with a random String.
Then:
import UIKit
import MapKit
class ViewController: UIViewController {
var locManager = CLLocationManager()
var currentLocation: CLLocation!
override func viewDidLoad() {
super.viewDidLoad()
locManager.requestWhenInUseAuthorization()
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways){
guard let currentLocation = locManager.location else {
return
}
print(currentLocation.coordinate.latitude)
print(currentLocation.coordinate.longitude)
}
}
}
Done.
Despite other advice you should use the CLLocationManagerDelegate to safely retrieve a location (without using it you may get null locations when the location manager doesn't have enough time to update). I strongly recommend wrapping the location manager code within a static shared helper (something along these lines):
class Locator: NSObject, CLLocationManagerDelegate {
enum Result <T> {
case .Success(T)
case .Failure(ErrorType)
}
static let shared: Locator = Locator()
typealias Callback = (Result <Locator>) -> Void
var requests: Array <Callback> = Array <Callback>()
var location: CLLocation? { return sharedLocationManager.location }
lazy var sharedLocationManager: CLLocationManager = {
let newLocationmanager = CLLocationManager()
newLocationmanager.delegate = self
// ...
return newLocationmanager
}()
// MARK: - Authorization
class func authorize() { shared.authorize() }
func authorize() { sharedLocationManager.requestWhenInUseAuthorization() }
// MARK: - Helpers
func locate(callback: Callback) {
self.requests.append(callback)
sharedLocationManager.startUpdatingLocation()
}
func reset() {
self.requests = Array <Callback>()
sharedLocationManager.stopUpdatingLocation()
}
// MARK: - Delegate
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
for request in self.requests { request(.Failure(error)) }
self.reset()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: Array <CLLocation>) {
for request in self.requests { request(.Success(self)) }
self.reset()
}
}
Then in view did load (or anywhere else you need to get the current location) run:
Locator.shared.locate { result in
switch result {
case .Success(locator):
if let location = locator.location { /* ... */ }
case .Failure(error):
/* ... */
}
}
In Swift
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
//Labels outlets
#IBOutlet var localityTxtField: UITextField!
#IBOutlet var postalCodeTxtField: UITextField!
#IBOutlet var aAreaTxtField: UITextField!
#IBOutlet var countryTxtField: UITextField!
let locationManager = CLLocationManager()
//View Didload
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
//Button Location
#IBAction func findMyLocation(_ sender: AnyObject) {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)->Void in
if (error != nil) {
print("Reverse geocoder failed with error" + (error?.localizedDescription)!)
return
}
if (placemarks?.count)! > 0 {
print("placemarks",placemarks!)
let pm = placemarks?[0]
self.displayLocationInfo(pm)
} else {
print("Problem with the data received from geocoder")
}
})
}
func displayLocationInfo(_ placemark: CLPlacemark?) {
if let containsPlacemark = placemark {
print("your location is:-",containsPlacemark)
//stop updating location to save battery life
locationManager.stopUpdatingLocation()
let locality = (containsPlacemark.locality != nil) ? containsPlacemark.locality : ""
let postalCode = (containsPlacemark.postalCode != nil) ? containsPlacemark.postalCode : ""
let administrativeArea = (containsPlacemark.administrativeArea != nil) ? containsPlacemark.administrativeArea : ""
let country = (containsPlacemark.country != nil) ? containsPlacemark.country : ""
localityTxtField.text = locality
postalCodeTxtField.text = postalCode
aAreaTxtField.text = administrativeArea
countryTxtField.text = country
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error while updating location " + error.localizedDescription)
}
}
In current thread a solution was proposed without delegate but in Xcode 9.1 testing in simulator it did not work, location was nil. This code worked:
import UIKit
import MapKit
class ViewController: UIViewController, CLLocationManagerDelegate {
var locationManager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
if (CLLocationManager.locationServicesEnabled())
{
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last! as CLLocation
/* you can use these values*/
let lat = location.coordinate.latitude
let long = location.coordinate.longitude
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I am junior but I solved it in this way:
I have created extension of my class inherited CLLocationManagerDelegate and following steps:
1.Import CoreLocation to your ViewController
import CoreLocation
2.Then initialize location manager and location variables inside your ViewController.
var locManager = CLLocationManager()
var currentUserLocation: CLLocation!
Inside viewDidLoad() request location init delegate and requestUsageDescription
locManager.requestWhenInUseAuthorization()
locManager.delegate = self
locManager.requestLocation()
Then I have just created extension for my viewController inheriting CLLocationManagerDelegate
extension theNameOfYourViewController: CLLocationManagerDelegate{
func locationManager(_ manager: CLLocationManager, didFailWithError error: Swift.Error) {
print(error)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// .requestLocation will only pass one location to the locations array
// hence we can access it by taking the first element of the array
if let location = locations.first {
print(location.coordinate.latitude)
print(location.coordinate.longitude)
}
}
}
Just remember to change the names according your needs also whenever you need location just use the function request location
locManager.requestLocation()
I agree with Kevin above, but if you're looking for less code for something simpler the following will suffice:
Make sure to use the CLLocationManagerDelegate
Swift 4:
In viewDidLoad you can add the following
locationManager.requestWhenInUseAuthorization()
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse) || (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways) {
currentLocation = locationManager.location
print(currentLocation.coordinate.latitude)
print(currentLocation.coordinate.longitude)
}
}
And for the first request respond once the user gives or denies permission:
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
locationManager.requestLocation()
currentLocation = locationManager.location
print(currentLocation.coordinate.latitude)
print(currentLocation.coordinate.longitude)
//Process location information and update.
}
Make sure to add the following keys to Info.plist:
Privacy - Location When In Use Usage Description
Privacy - Location Always and When In Use Usage Description
Create User class:
import Foundation
import CoreLocation
import MapKit
class User: NSObject, ObservableObject {
#Published var position = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
let manager = CLLocationManager()
override init() {
super.init()
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.requestLocation()
}
}
extension User: CLLocationManagerDelegate {
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
print("Location services authorization request")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("User location updated")
print("Updated position: \(locations.first?.coordinate.latitude ?? 00)")
if let location = locations.first {
self.position = location.coordinate
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Failed to find user's location: \(error.localizedDescription)")
}
}
Update
Swift 5+
Xcode 13+
Add these permission in info plist
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs your location to show nearby services</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs your location to show nearby services</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs your location to show nearby services</string>
Import this in your view controller
import CoreLocation
in viewDidLoad()
override func viewDidLoad() {
locationManager.requestWhenInUseAuthorization()
locationManager.requestLocation()
}
Create extension like this
extension RegisterViewController : CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("error:: \(error.localizedDescription)")
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
locationManager.requestLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let locationSafe = locations.last {
locationManager.stopUpdatingLocation()
let latitude = locationSafe.coordinate.latitude
let longitude = locationSafe.coordinate.longitude
self.currentLatitude = latitude
self.currentLongitude = longitude
print(" Lat \(latitude) , Longitude \(longitude)")
}
if locations.first != nil {
print("location:: \(locations[0])")
}
}
}
Run and check this

Resources