2012-07-16 13 views
16

Tengo múltiples controladores de vista que necesitan obtener la ubicación del usuario, así que quería crear una clase separada a la que los ViewControllers puedan llamar para obtener la ubicación más reciente del usuario.iOS CLLocationManager en una clase separada

locationManager: didUpdateToLocation: fromLocation devuelve void. ¿Cómo transfiero los datos de latitud y longitud a mis ViewControllers tan pronto como se calcule la latitud y la longitud del usuario?

Podría intentar escribir getters y setters en mi clase LocationManaging, pero si hago eso, ¿cómo sé cuándo llamar a los métodos getter de latitud y longitude getter de mi clase ViewController? ¿Cómo sostengo el hilo principal de ViewController para esperar los valores de latitud y longitud de la clase locationManaging?

Gracias!

+0

'locationManager: didUpdateToLocation: fromLocation' es un método delegado. El administrador de la ubicación usa este método para informar a su objeto que la ubicación se actualizó con un nuevo valor; usted debe implementar este método para hacer algo con el valor. – quellish

Respuesta

14

Crea una clase singleton que tiene propiedades latitude y longitude, startLocating y endLocating. En la clase, cree una instancia CLLocationManager y configure su delegado como singleton. En startLocating y endLocating, llame a los métodos apropiados de la instancia CLLocationManager. Haga que los métodos de delegado actualicen las propiedades latitude y longitude. En el otro ViewControllers, lea las propiedades latitude y longitude de este singleton.

saber cuándo hay que leer las propiedades de otro ViewController, establece un observador en estas propiedades (ver el NSKeyValueObserving Protocol Reference

Antes de hacer esto, mira hacia arriba la Internets para el código existente.

Después de hacer esto, cargados a GitHub con una licencia permisiva.

+0

gracias! mi pregunta de seguimiento es ... ¿cómo sé cuándo mi ViewController debería llamar a las propiedades de latitud y longitud del singleton? En otras palabras, ¿cómo puedo bloquear mi hilo principal de ViewController que esperar a que los valores de Lat Long válidos en mi Singleton – user1467188

+0

Está en el segundo párrafo (podría haber añadido que mientras estaba leyendo mi mensaje inicial) – user1071136

+0

accede a las propiedades singletons en el interior del los observadores cambian el método de notificación – nilloc

23

Como user1071136 dicho, un gerente de locación Singleton es probablemente lo que quiere. Crear una clase, una subclase de NSObject, con sólo 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 recibido más recientemente, basta con utilizar [LocationManagerSingleton sharedSingleton].locationManager.location. Puede llevar unos segundos calentar el GPS para obtener ubicaciones precisas.

+6

Puede que desee actualizar su bloque @synchronized a 'dispatch_once'. – user

+0

@Rickay ¿Este resultado volverá en caso de modo avión? –

+0

Si marca esta respuesta: (http://stackoverflow.com/questions/7376294/how-is-it-that-cllocationmanager-gets-a-location-when-airplane-mode-is-on) encontrará que en este caso, 'CLLocationManager' devuelve la ubicación adquirida más recientemente, pero no la información de ubicación nueva. –

3

Esto es lo que hice al implementar un administrador de ubicaciones singleton en swift. Se basa en la estrategia de user1071136, así como en this swift pattern.

// 
// 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() 
+5

Use mitones para horno cuando use un dispositivo con este código. – quellish

+0

Actualmente estoy tratando de usar su clase, pero la aplicación nunca solicita autorización ni obtengo una ubicación. ¿Qué debo hacer para usar la clase? – Thomas

+0

Nunca olvides el info.plst: http://stackoverflow.com/questions/24050633/implement-cllocationmanagerdelegate-methods-in-swift/24056771#24056771 – Thomas

4

Con base en las respuestas anteriores, esto es lo que hice y se puede encontrar el ejemplo completo en github https://github.com/irfanlone/CLLocationManager-Singleton-Swift

Sólo tiene que importar este archivo en su proyecto, entonces usted puede optar por aplicar la LocationUpdateProtocol o escuchar a 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)") 
    } 

} 
0

En el proceso de aprender a obtener la ubicación del usuario en una clase singleton, descargué este código https://github.com/irfanlone/CLLocationManager-Singleton-Swift. Después de forzarlo para que funcione en Xcode8.3.3 Swift 3, no puedo obtener ningún resultado en la consola de depuración. De hecho, ni siquiera puedo obtener este dlalog de autenticación de la ubicación para mostrar. Sospecho que los datos del singleton no se pasan al controlador de vista, pero no puedo solucionar la solución, ¿puedes ver lo que está mal? Gracias.

El código corregido para Swift 3 es: // El singleton: importación MapKit

protocolo LocationUpdateProtocol { func locationDidUpdateToLocation (_ ubicación: CLLocation) }

dejar kLocationDidChangeNotification = "LocationDidChangeNotification"

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

}

// El ViewController UIKit importación CoreLocation importación

ViewController clase: 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)") 
} 

}

+0

Debe considerar hacer una pregunta usted mismo en lugar de publicar su pregunta como una respuesta. – stephenmuss

+0

Gracias por nada. Si comienzo una nueva pregunta con un título similar. tu chico lo marca como duplicado! – Rich

Cuestiones relacionadas