Какой самый простой способ узнать текущее местоположение iPhone? - PullRequest
22 голосов
/ 20 января 2009

Я уже знаю, как использовать CLLocationManager, так что я мог бы сделать это трудным путем, с делегатами и всем этим.

Но я хотел бы иметь удобный метод, который просто получает текущее местоположение, один раз и блокирует, пока не получит результат.

Ответы [ 5 ]

45 голосов
/ 20 января 2009

Что я делаю, так это реализую одноэлементный класс для управления обновлениями из основного местоположения. Чтобы получить доступ к моему текущему местоположению, я делаю CLLocation *myLocation = [[LocationManager sharedInstance] currentLocation]; Если вы хотите заблокировать основной поток, вы можете сделать что-то вроде этого:

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
}

Однако, как уже отмечалось, блокировка основного потока, вероятно, не очень хорошая идея, но это может быть хорошей отправной точкой, когда вы что-то строите. Вы также заметите, что класс, который я написал, проверяет временную метку обновления местоположения и игнорирует все старые, чтобы предотвратить проблему получения устаревших данных из основного местоположения.

Это единственный класс, который я написал. Обратите внимание, что это немного шероховато по краям:

#import <CoreLocation/CoreLocation.h>
#import <Foundation/Foundation.h>

@interface  LocationController : NSObject <CLLocationManagerDelegate> {
    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
7 голосов
/ 22 января 2009

Нет такого удобства, и вы не должны создавать свои собственные. «Блокирует до тех пор, пока не получит результат» - это крайне плохая практика программирования на таком устройстве, как iPhone. Это может занять несколько секунд, чтобы получить местоположение; вы никогда не должны заставлять своих пользователей так ждать, а делегаты гарантируют, что они этого не сделают.

4 голосов
/ 20 января 2009

«Удобных методов» не существует, если вы сами их не кодируете, но вам все равно нужно реализовать методы делегата в любом пользовательском коде, который вы используете, чтобы сделать вещи «удобными».

Шаблон делегата существует по определенной причине, и, поскольку делегаты являются важной частью Objective-C, я рекомендую вам освоиться с ними.

0 голосов
/ 14 октября 2013

Я упростил и объединил несколько ответов, где местоположение обновляется только в том случае, если оно действительно.

Он также работает под OSX и iOS.

Это предполагает случай использования, когда текущее местоположение неожиданно становится желательным для пользователя. Если в этом примере это занимает более 100 мс, это считается ошибкой. (Предполагается, что GPS IC & | Wifi (клон Apple Skyhook) уже запущен и уже исправлен.)

#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

0 голосов
/ 29 июня 2013

Я оценил ответ Брэда Смита. Реализуя его, я обнаружил, что один из методов, которые он использует, устарел с iOS6. Чтобы написать код, который будет работать как с iOS5, так и с iOS6, используйте следующее:

- (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];
}
...