¿Cuál es la forma más fácil de obtener la ubicación actual de un iPhone?

Ya sé cómo usar CLLocationManager, así que podría hacerlo de la manera difícil, con delegates y todo eso.

Pero me gustaría tener un método de conveniencia que simplemente obtenga la ubicación actual, una vez, y bloques hasta que obtenga el resultado.

Lo que hago es implementar una clase singleton para administrar las actualizaciones desde la ubicación central. Para acceder a mi ubicación actual, hago una CLLocation *myLocation = [[LocationManager sharedInstance] currentLocation]; Si quisiera bloquear el hilo principal, podría hacer algo como esto:

 while ([[LocationManager sharedInstance] locationKnown] == NO){ //blocking here //do stuff here, dont forget to have some kind of timeout to get out of this blocked //state } 

Sin embargo, como ya se ha señalado, bloquear el hilo principal probablemente no sea una buena idea, pero este puede ser un buen punto de partida para construir algo. También notará que la clase que escribí verifica la marca de tiempo en las actualizaciones de ubicación e ignora las que son antiguas, para evitar el problema de obtener datos obsoletos desde la ubicación del núcleo.

Esta es la clase singleton que escribí. Tenga en cuenta que es un poco difícil en los bordes:

 #import  #import  @interface LocationController : NSObject  { CLLocationManager *locationManager; CLLocation *currentLocation; } + (LocationController *)sharedInstance; -(void) start; -(void) stop; -(BOOL) locationKnown; @property (nonatomic, retain) CLLocation *currentLocation; @end @implementation LocationController @synthesize currentLocation; static LocationController *sharedInstance; + (LocationController *)sharedInstance { @synchronized(self) { if (!sharedInstance) sharedInstance=[[LocationController alloc] init]; } return sharedInstance; } +(id)alloc { @synchronized(self) { NSAssert(sharedInstance == nil, @"Attempted to allocate a second instance of a singleton LocationController."); sharedInstance = [super alloc]; } return sharedInstance; } -(id) init { if (self = [super init]) { self.currentLocation = [[CLLocation alloc] init]; locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; [self start]; } return self; } -(void) start { [locationManager startUpdatingLocation]; } -(void) stop { [locationManager stopUpdatingLocation]; } -(BOOL) locationKnown { if (round(currentLocation.speed) == -1) return NO; else return YES; } - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { //if the time interval returned from core location is more than two minutes we ignore it because it might be from an old session if ( abs([newLocation.timestamp timeIntervalSinceDate: [NSDate date]]) < 120) { self.currentLocation = newLocation; } } - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { UIAlertView *alert; alert = [[UIAlertView alloc] initWithTitle:@"Error" message:[error description] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; [alert release]; } -(void) dealloc { [locationManager release]; [currentLocation release]; [super dealloc]; } @end 

No hay tal conveniencia y no debes crear la tuya propia. “Bloquea hasta obtener el resultado” es una práctica de progtwigción extremadamente mala en un dispositivo como el iPhone. Puede llevar unos segundos recuperar una ubicación; nunca debe hacer que sus usuarios esperen así, y los delegates se aseguran de que no lo hagan.

No hay “métodos de conveniencia” a menos que los codifique usted mismo, pero igual tendría que implementar los métodos de delegado en cualquier código personalizado que use para hacer las cosas “convenientes”.

El patrón de delegates está ahí por una razón, y como los delegates son una gran parte de Objective-C, les recomiendo que se sientan cómodos con ellos.

Aprecié la respuesta de Brad Smith. Implementándolo Descubrí que uno de los métodos que emplea está obsoleto a partir de iOS6. Para escribir código que funcione con iOS5 e iOS6, use lo siguiente:

 - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { if (abs([[locations lastObject] timeIntervalSinceDate:[NSDate date]]) < 120) { [self setCurrentLocation:[locations lastObject]]; } } // Backward compatibility with iOS5. - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { NSArray *locations = [NSArray arrayWithObjects:oldLocation, newLocation, nil]; [self locationManager:manager didUpdateLocations:locations]; } 

Simplifiqué y combiné varias respuestas para que la ubicación solo se actualice si es válida.

También funciona con OSX e iOS.

Esto supone el caso de uso en el que el usuario desea de repente la ubicación actual. Si lleva más de 100 ms en este ejemplo, se considera un error. (Asume que el GPS IC & | Wifi (el clon Skyhook de Apple) ya está encendido y ya tiene una buena solución).

 #import "LocationManager.h" // wait up to 100 ms CLLocation *location = [LocationManager currentLocationByWaitingUpToMilliseconds:100]; if (!location) { NSLog(@"no location :("); return; } // location is good, yay 

https://gist.github.com/6972228