2009-01-19 3 views
22

CLLocationManager를 사용하는 방법을 이미 알고 있으므로 대리인을 비롯한 모든 사람들이 힘들게 할 수 있습니다.iPhone의 현재 위치를 가져 오는 가장 쉬운 방법은 무엇입니까?

하지만 지금까지 한 번만 현재 위치를 얻는 편리한 방법을 원합니다. 그리고 결과를 얻을 때까지 차단합니다.

+0

| (이미 와이파이 (애플의 스카이 훅 클론)가 이미 해고되고 좋은 수정이있는 GPS IC &가 가정합니다.) 그런 "편의 방법"을 구현하는 데있어 어떤 문제가 있습니까? – tcurdt

+10

나는 문제가 그렇게 쉽지 않다고 생각한다. 일반적으로 그것은 오래된 위치를 먼저 반환하고, 격렬하게 무적 인 것을 뒤 따르고, 점진적으로 더 좋은 것을 뒤 따르는데, 어느 시점에서 원하는 위치를 찾았습니까? 그것은 당신에게 달려 있습니다. – rustyshelf

+0

좋은 지적, 녹슨! –

답변

4

직접 코드를 작성하지 않으면 "편리한 방법"이 없지만 "편리한"사용자 지정 코드로 위임 메서드를 구현해야합니다.

델리게이트 패턴은 이유가 있으며, 델리게이트는 Objective-C의 큰 부분이므로, 익숙해 지길 권한다.

45

내가하는 일은 코어 위치에서 업데이트를 관리하는 싱글 톤 클래스를 구현하는 것입니다. 이미 지적 된 바와 같이, 메인 스레드를 차단하는 것은 아마 아닙니다,

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 
} 

그러나 내 현재 위치를 액세스하려면, 당신은 당신이 이런 일을 할 수있는 메인 스레드를 차단하고 싶었 경우 CLLocation *myLocation = [[LocationManager sharedInstance] currentLocation]; 할 좋은 생각이긴하지만, 뭔가를 짓고있는 시점에서 좋은 점프가 될 수 있습니다. 또한 내가 작성한 클래스가 위치 업데이트에 대한 타임 스탬프를 확인하고 오래된 위치는 무시하므로 코어 위치에서 부실 데이터를 가져 오는 문제를 방지 할 수 있습니다.

이것은 내가 작성한 싱글 톤 클래스입니다. 가장자리 주위가 약간 거친 점에 유의하십시오.

#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 
+0

이 솔루션을 이용해 주셔서 감사합니다. 그것은 사용할 수있는 좋은 작은 컨트롤러입니다.내가 찾은 한 가지는 locationKnown 메소드가 정확하지 않다는 것입니다. 즉, currentLocation이 init 메소드에서 초기화되었으므로 항상 YES를 반환했습니다. 다음은 speed 속성을 사용하여 사용자 위치 수신 여부를 결정하는 메서드의 다른 버전입니다. - (BOOL) locationKnown { if (round (currentLocation.speed) == -1) return NO; else return 예; } –

+3

코드를 편집했습니다. 올바르게 이해했으면합니다. –

+2

리소스를 할당했지만 배포하지 않았습니다. 당신은 어떤 문제를 일으키지 않을 것이라고 당신이 어디에서 풀어 줄 것인지 말해 주시겠습니까? –

7

그런 편의가 없으므로 직접 작성해서는 안됩니다. "결과가 나올 때까지 차단"은 입니다. iPhone과 같은 기기의 프로그래밍 연습은 극히 불량합니다 (). 위치를 검색하는 데 몇 초가 걸릴 수 있습니다. 사용자가 그런 식으로 기다리게해서는 안되며, 위임자는 사용자가 기다리지 않도록해야합니다.

+1

그게 무슨 스레드가 아닌가요? –

+0

완료시 콜백과 결합 된 스레드 (예)입니다. 콜백은 원래 실행 루프에서 예약됩니다. 어느 CLLocationManager의 델리게이트 (delegate)와 같은 인터페이스를 제공합니다. "Block until done"은 최종 사용자 앱에서는 좋은 디자인이 아닙니다. –

+18

나는 "완료 될 때까지 차단"은 모든 종류의 앱에서 많은 합법적 인 사용을하고 있으며, "완료 될 때까지 UI가 멈추는"것과 ​​동의어가 아닙니다. * 모든 것을 * 비동기로 만들려고하면 기괴한 행동과 버그가있는 앱으로 이어집니다. UI가 얼마나 빨리 표시되는지/표시해야하는 정보가 아직 제공되지 않는 경우 누가 응답합니까? 비동기 작업이 자리를 잡으므로 비동기 작업도 차단됩니다. 하나가 좋고 다른 하나가 나쁘지 않은 경우는 아닙니다. – aroth

0

나는 Brad Smith의 대답을 높이 평가했다. 이를 구현하면서 그가 사용하는 방법 중 하나는 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]; 
} 
0

나는 간단하고 유효하다면 위치 만 업데이트되는 경우 여러 답변을 결합했다.

OSX 및 iOS에서도 작동합니다.

여기서는 사용자가 현재 위치를 갑자기 원하는 경우를 가정합니다. 이 예제에서 100ms 이상 걸리면 오류로 간주됩니다. 당신이 CLLocationManager를 사용하는 방법을 알고있는 경우 : -

#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

잘 작동합니다! –