corelocation - iOS CLLocationManager en una clase separada
corelocation swift 4 (5)
Tengo varios controladores de vista que necesitan obtener la ubicación del usuario, así que quise crear una clase separada a la que los ViewControllers puedan llamar para obtener la ubicación más reciente del usuario.
locationManager: didUpdateToLocation: fromLocation devuelve void. ¿Cómo transfiero los datos de latitud y longitud a mis ViewControllers tan pronto como se calcula la latitud y longitud del usuario?
Podría intentar escribir captadores y definidores en mi clase de gestión de ubicación, pero si lo hago, ¿cómo puedo saber cuándo llamar a los métodos de captador de latitud y captador de longitud desde mi clase ViewController? ¿Cómo puedo mantener el hilo principal de ViewController para esperar los valores de latitud y longitud de la clase locationManaging?
¡Gracias!
Como dijo el usuario 1071136, un administrador de ubicación de singleton es probablemente lo que quieres. Cree una clase, una subclase de NSObject, con solo una propiedad, un CLLocationManager
.
LocationManagerSingleton.h:
#import <MapKit/MapKit.h>
@interface LocationManagerSingleton : NSObject <CLLocationManagerDelegate>
@property (nonatomic, strong) CLLocationManager* locationManager;
+ (LocationManagerSingleton*)sharedSingleton;
@end
LocationManagerSingleton.m:
#import "LocationManagerSingleton.h"
@implementation LocationManagerSingleton
@synthesize locationManager;
- (id)init {
self = [super init];
if(self) {
self.locationManager = [CLLocationManager new];
[self.locationManager setDelegate:self];
[self.locationManager setDistanceFilter:kCLDistanceFilterNone];
[self.locationManager setHeadingFilter:kCLHeadingFilterNone];
[self.locationManager startUpdatingLocation];
//do any more customization to your location manager
}
return self;
}
+ (LocationManagerSingleton*)sharedSingleton {
static LocationManagerSingleton* sharedSingleton;
if(!sharedSingleton) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedSingleton = [LocationManagerSingleton new];
}
}
return sharedSingleton;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
//handle your location updates here
}
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
//handle your heading updates here- I would suggest only handling the nth update, because they
//come in fast and furious and it takes a lot of processing power to handle all of them
}
@end
Para obtener la ubicación recibida más recientemente, simplemente use [LocationManagerSingleton sharedSingleton].locationManager.location
. Puede llevar unos segundos calentar el GPS para obtener ubicaciones precisas.
Cree una clase singleton que tenga propiedades de latitude
y longitude
, startLocating
y endLocating
. En la clase, cree una instancia de CLLocationManager
y establezca su delegado para que sea el singleton. En startLocating
y endLocating
, llame a los métodos apropiados de la instancia de CLLocationManager
. Haga que los métodos delegados actualicen las propiedades de latitude
y longitude
. En otros ViewControllers
, lea las propiedades de latitude
y longitude
este singleton.
Para saber cuándo leer esas propiedades de otro ViewController
, configure un observador en estas propiedades (consulte la Referencia del protocolo NSKeyValueObserving
Antes de hacer esto, busque en Internet los códigos existentes.
Después de hacer esto, cárguelo a GitHub con una licencia permisiva.
En base a las respuestas anteriores, esto es lo que hice y puede encontrar el ejemplo completo en github https://github.com/irfanlone/CLLocationManager-Singleton-Swift
Solo importa este archivo en tu proyecto, entonces puedes elegir implementar el LocationUpdateProtocol o escuchar la notificación de actualizaciones de ubicación.
import MapKit
protocol LocationUpdateProtocol {
func locationDidUpdateToLocation(location : CLLocation)
}
/// Notification on update of location. UserInfo contains CLLocation for key "location"
let kLocationDidChangeNotification = "LocationDidChangeNotification"
class UserLocationManager: NSObject, CLLocationManagerDelegate {
static let SharedManager = UserLocationManager()
private var locationManager = CLLocationManager()
var currentLocation : CLLocation?
var delegate : LocationUpdateProtocol!
private override init () {
super.init()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = kCLLocationAccuracyHundredMeters
locationManager.requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
}
// MARK: - CLLocationManagerDelegate
func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
currentLocation = newLocation
let userInfo : NSDictionary = ["location" : currentLocation!]
dispatch_async(dispatch_get_main_queue()) { () -> Void in
self.delegate.locationDidUpdateToLocation(self.currentLocation!)
NSNotificationCenter.defaultCenter().postNotificationName(kLocationDidChangeNotification, object: self, userInfo: userInfo as [NSObject : AnyObject])
}
}
}
Uso:
class ViewController: UIViewController, LocationUpdateProtocol {
var currentLocation : CLLocation!
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "locationUpdateNotification:", name: kLocationDidChangeNotification, object: nil)
let LocationMgr = UserLocationManager.SharedManager
LocationMgr.delegate = self
}
// MARK: - Notifications
func locationUpdateNotification(notification: NSNotification) {
let userinfo = notification.userInfo
self.currentLocation = userinfo!["location"] as! CLLocation
print("Latitude : /(self.currentLocation.coordinate.latitude)")
print("Longitude : /(self.currentLocation.coordinate.longitude)")
}
// MARK: - LocationUpdateProtocol
func locationDidUpdateToLocation(location: CLLocation) {
currentLocation = location
print("Latitude : /(self.currentLocation.coordinate.latitude)")
print("Longitude : /(self.currentLocation.coordinate.longitude)")
}
}
En el proceso de aprender a obtener la ubicación del usuario en una clase de singleton, descargué este código https://github.com/irfanlone/CLLocationManager-Singleton-Swift . Después de jugar con él para ejecutarlo en Xcode8.3.3 Swift 3, no puedo obtener ningún resultado en la consola de depuración. De hecho, ni siquiera puedo mostrar este dlalog de automatización de ubicación. Sospecho que los datos del singleton no se pasan al controlador de vista, pero no puedo encontrar la solución, ¿puede ver qué está mal? Gracias.
El código corregido para Swift 3 es:
//The singleton:
import MapKit
protocol LocationUpdateProtocol {
func locationDidUpdateToLocation(_ location : CLLocation)
}
let kLocationDidChangeNotification = "LocationDidChangeNotification"
class UserLocationManager: NSObject, CLLocationManagerDelegate {
static let SharedManager = UserLocationManager()
fileprivate var locationManager = CLLocationManager()
var currentLocation : CLLocation?
var delegate : LocationUpdateProtocol!
fileprivate override init () {
super.init()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = kCLLocationAccuracyHundredMeters
locationManager.requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
}
// MARK: - CLLocationManagerDelegate
func locationManager(manager: CLLocationManager,didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
currentLocation = newLocation
let userInfo : NSDictionary = ["location" : currentLocation!]
DispatchQueue.main.async() { () -> Void in
self.delegate.locationDidUpdateToLocation(self.currentLocation!)
NotificationCenter.default.post(name: Notification.Name(kLocationDidChangeNotification), object: self, userInfo: userInfo as [NSObject : AnyObject])
}
}
}
// The ViewController
import UIKit
import CoreLocation
class ViewController: UIViewController, LocationUpdateProtocol {
var currentLocation : CLLocation!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.locationUpdateNotification(_:)), name: NSNotification.Name(rawValue: kLocationDidChangeNotification), object: nil)
let LocationMgr = UserLocationManager.SharedManager
LocationMgr.delegate = self
}
// MARK: - Notifications
func locationUpdateNotification(_ notification: Notification) {
let userinfo = notification.userInfo
self.currentLocation = userinfo!["location"] as! CLLocation
print("Latitude : /(self.currentLocation.coordinate.latitude)")
print("Longitude : /(self.currentLocation.coordinate.longitude)")
}
// MARK: - LocationUpdateProtocol
func locationDidUpdateToLocation(_ location: CLLocation) {
currentLocation = location
print("Latitude : /(self.currentLocation.coordinate.latitude)")
print("Longitude : /(self.currentLocation.coordinate.longitude)")
}
}
Esto es lo que hice cuando implementé un administrador de ubicación singleton en swift. Se basa en la estrategia del usuario1071136, así como en este patrón veloz .
//
// UserLocationManager.swift
//
// Use: call SharedUserLocation.currentLocation2d from any class
import MapKit
class UserLocation: NSObject, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
// You can access the lat and long by calling:
// currentLocation2d.latitude, etc
var currentLocation2d:CLLocationCoordinate2D?
class var manager: UserLocation {
return SharedUserLocation
}
init () {
super.init()
if self.locationManager.respondsToSelector(Selector("requestAlwaysAuthorization")) {
self.locationManager.requestWhenInUseAuthorization()
}
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = 50
self.locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
self.currentLocation2d = manager.location.coordinate
}
}
let SharedUserLocation = UserLocation()