CLLocation Manager en Swift para obtener la ubicación del Usuario


Estoy tratando de convertir una aplicación antigua en ObjC a Swift como un ejercicio de práctica y me he topado con algunos problemas. La forma en que lo tenía en la aplicación anterior, era establecer el Administrador de CLLocation y luego usaría:

manager = [[CLLocationManager alloc]init];
manager.delegate = self;
manager.desiredAccuracy = kCLLocationAccuracyBest;    
[manager startUpdatingLocation]

Que llamaría automáticamente:

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
}

Y de ahí pude extraer toda la información que necesitaba. Pero en swift, no hay autocompletado de este método y no puedo averiguar cómo reproducirlo. La documentación dice que

startUpdatingLocation()

Will todavía ser llamado por el delegado, pero no está sucediendo.

Esto es lo que tengo hasta ahora:

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"
}
}

Cualquier ayuda o sugerencia sobre dónde buscar sería apreciada. Gracias.

EDITAR: Actualizado a partir de Sugerencias, pero aún no funciona

EDIT2: Parece haber algún error que no permite que el método funcione correctamente en ViewController

Author: Sean Fitz, 2014-06-05

11 answers

Te faltan dos cosas. Primero, tienes que pedir permiso usando requestAlwaysAuthorization o requestWhenInUseAuthorization(). Así que su viewDidLoad() debe ser así:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    locationManager = CLLocationManager()
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestAlwaysAuthorization()
    locationManager.startUpdatingLocation()
}

En segundo lugar, edite su Info.plist como se indica aquí .

 59
Author: danilopez.dev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:24

Primero agregue estas dos líneas en el archivo plist

1) NSLocationWhenInUseUsageDescription

2) NSLocationAlwaysUsageDescripción

Entonces esto es trabajo de clase completa implementar esto

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)")
        }
}
}
 19
Author: jayesh kavathiya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-11 12:30:56

No estoy seguro de por qué, pero parece que startUpdatingLocation no está presentando el mensaje de usuario en el simulador de iOS 7, pero cuando lo habilité manualmente funcionó como se esperaba si usaba la forma más reciente del método delegado:

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)")
}

El formato que está utilizando ha sido obsoleto desde iOS 5 o 6, por lo que aparentemente no es compatible en absoluto con las capas de puente swift.

 6
Author: David Berry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-02 16:24:54

Tuvo el mismo problema. didUpdateLocations - no estaba funcionando. Ejecuta tu aplicación. Vaya a la página Configuración -> Privacidad -> Ubicación y desactive los Servicios de ubicación. didFailWithError detectará el error sobre los servicios de ubicación ausentes. Entonces enciéndelo. Desde ese momento didUpdateLocations capturará ubicaciones.

 3
Author: salty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-06 18:26:39

Espero que haya dos maneras.

    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()
}

Implementando 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

  }

Comprobación de la autorización de CLLocationDelegate:

 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

        }
      }

Nota: changeStatusToOn o changeStatusToOff es un método UILabel Extenion que activa/desactiva el texto de la etiqueta con colores Verde/Rojo.

 2
Author: A.G,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-31 08:39:00

Aquí está mi código muy simple que funciona:

Primero agregue Core Location framework en General/Linked Frameworks and Libraries

Luego agrega lo siguiente en Info.plist:

<key>NSLocationWhenInUseUsageDescription</key>
<string>blablabla</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>blablabla</string>

Este es mi ViewController.archivo swift:

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)")
    }

}
 2
Author: Jarda Pavlíček,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-18 10:27:26

Para 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)")
    }


}
 2
Author: Steffen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-08 12:03:55

No olvides agregar Nslocación cuando se utiliza la descripción del uso o Descripción de Nslocationalwaysusaged en su archivo de configuración (target/Info/custom iOS target properties

 1
Author: Vassily,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-15 10:17:32

Agregue la propiedad 2 a continuación en la información .plist

NSLocationWhenInUseUsageDescription : Location information is used for fraud prevention

Privacy - Location Usage Description : Location information is used for fraud prevention
 0
Author: Mitul Marsoniya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-21 11:01:38

Si desea actualizar la ubicación del usuario de forma predeterminada, sin hacer clic en 'Simular ubicación' cada vez, vaya a

YourProject-->Build Phases-->Link Binary with libraries-->Add corelocation.framework

La ubicación se actualiza automáticamente por defecto cuando se ejecuta la aplicación en el simulador. Probado y funciona en Swift 2 !

 0
Author: Naishta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-25 20:26:18

Esto solicitará permiso y rastreará si se le da permiso para salir con una alerta. Detiene el seguimiento al presionar el botón atrás.

Info.plist

<key>NSLocationAlwaysUsageDescription</key>
<string>Allow tracking while completing a survey</string>

Clase:

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)
            })
        }

    }
 0
Author: Gary Davies,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-16 02:11:51