본문 바로가기
프로그래밍/iOS

위치정보를 이용하는 어플 예제

by 백룡화검 2012. 1. 16.

GPS리시버를 사용하여 우주에 떠 있는 인공위성을 통해 현재 위치를 간단하게 알 수 있다. 단, GPS리시버가 정확하게 처리되게 만들려면 GPS신호 수신 가능범위에 있어야 한다. 그래서 건물내에서는 불가능하다.


그 외 자신의 위치를 아는 방법중 하나는 휴대전화의 안테나에 의한 삼각측량방법이 있다. 대기 상태의 휴대전화는 범위내 기지국에 연결한 상태를 가지고 있다. 그런 안테나탑 ID를 알 수 있다면, 안테나탑ID와 지리적 위치가 기록된 데이터베이스를 사용하여 물리적인 위치를 계산할 수 있다. GPS와 달리, 안테나탑 삼각측량은 위성을 사용하지 않기 때문에 실내에서 사용가능하다. 단, 이 방법으로 계산된 위치정보는 자신이 있는 영역내 안테나탑 끼리 간격에 좌우되므로, GPS만큼 정확하지는 않다. 이 방법은 안테나탑이 조밀하게 배치된 지역에서만 유용하다고 볼 수 있다.


최근에는 Wi-Fi삼각측량을 이용하는 방법이 나왔는데 이 방법은 기기가 Wi-Fi네트워크에 연결하여 데이터베이스로 서비스 프로바이더를 체크하여 해당 프로바이더가 서비스를 제공하고 있는 위치를 정한다. 이 방법은 삼각측량도 위성도 필요하지 않기 때문에 기기가 Wi-Fi만 잘 접속하면 가능한 일이지만, 가장 오차가 크다.


Core Location프레임웍

아이폰은 애플이 제공하는 Core Location프레임웍을 사용하여 물리적인 위치를 알 수 있다. 이 프레임웍의 장점은 앞에서 소개한 3가지 방법을 모두 이용하는 것도 제공한다는 것이다. 프레임웍을 사용하는 사용자는 어떤 방법이 사용될지 상관할 필요가 없다. 단지 필요한 정보처리를 방법을 지정하여 원하는 결과를 얻기 위한 최적화된 방법이 Core Location에 의해 구분된다.


좌표정보 얻기

Xcode 를 실행하고 View-based application프로젝트를 만들고 GPSLocation이라고 만들자. 우선 GPSLocationViewController.xib파일을 더블클릭하여 Interface Builder를 실행하고 

라벨과 텍스트필드를 아래와 같이 추가하자.


 

Xcode로 돌아와, Frameworks그룹에서 오른쪽 버튼을 클릭하고 [Add]-[Existing Frameworks]를 선택하고 'CoreLocation.framework'를 선택한다.

GPSLocationViewController.h에 아래 코드를 추가하자.

 #import <UIKit/UIKit.h>

#import <CoreLocation/CoreLocation.h>


@interface GPSLocationViewController : UIViewController <CLLocationManagerDelegate> {

IBOutlet UITextField *latiTextField;

IBOutlet UITextField *longiTextField;

IBOutlet UITextField *accuTextField;

CLLocationManager *lm;

}


@property(nonatomic, retain) UITextField *latiTextField;

@property(nonatomic, retain) UITextField *longiTextField;

@property(nonatomic, retain) UITextField *accuTextField;


@end


CLLocationManager클래스를 사용하면 뷰컨트롤러로 CLLocationManagerDelegate프로토콜을 추가해야한다. 또한 View창의 3개 텍스트필트 뷰에 접속하는 3개 아웃렛도 만들어야 한다.


Interface Builder로 가서  Control키를 누르고 [FIle's Owner]를 선택하고 3개의 텍스트필드 뷰의 각각에 드러그하고 각각 latiTextField, longiTextField, accuTextField를 선택한다. 아래코드를 GPSLocationViewController.m파일에 추가한다.

 @implementation GPSLocationViewController


@synthesize latiTextField, longiTextField, accuTextField;


-(void) viewDidLoad {

lm = [[CLLocationManager alloc] init];

if([lm locationServicesEnabled]) {

lm.delegate = self;

lm.desiredAccuracy = kCLLocationAccuracyBest;

lm.distanceFilter = 1000.0f;

[lm startUpdatingLocation];

}

}


-(void) locationManager: (CLLocationManager *) manager

  didUpdateToLocation: (CLLocation *) newLocation

  fromLocation: (CLLocation *) oldLocation {

NSString *lat = [[NSString alloc] initWithFormat:@"%g", newLocation.coordinate.latitude];

latiTextField.text = lat;

NSString *lng = [[NSString alloc] initWithFormat:@"%g", newLocation.coordinate.longitude];

longiTextField.text = lng;

NSString *acc = [[NSString alloc] initWithFormat:@"%g", newLocation.horizontalAccuracy];

accuTextField.text = acc;

[acc release];

[lat release];

[lng release];

}


-(void) locationManager: (CLLocationManager *) manager didFailWithError: (NSError *) error {

NSString *msg = [[NSString alloc] initWithString:@"Error obtaining location"];

UIAlertView *alert = [[UIAlertView alloc] initWithTitle: @"Error" message:msg delegate:nil cancelButtonTitle:@"확인otherButtonTitle:nil];

[alert show];

[msg release];

[alert release];

}


- (void)dealloc {

[lm release];

[latiTextField release];

[longiTextField release];

[accuTextField release];

    [super dealloc];

}



위 코드는 뷰로드시,  CLLocationManager클래스 인스턴스가 만들어지고, 이 객체를 사용하기 전에 사용자가 기기상의 로케이션 서비스를 사용할지 확인하게 된다. 이런 여부를 확인하는 것이 바로 desiredAccuracy속성을 사용해서 설정할 수 있으며 이런 옵션 설정에 kCLLocationAccuracyBest를 선언했다.

참고로 최고 설정을 해도 괜찮지만, 그 정도가 보증된 것은 아니다. 또한 필요이상 정도 위치를 지정하면 기기 배터리와 시간이 낭비된다.

distanceFilter 속성은 위치  업데이트를 실행하는 거리간격을 지정한 것으로 단위는 미터(m)이다. 작은 공간에서 이동도 위치 업데이트를 하려면, kCLDistanceFilterNone정수를 지정한다. 마지막으로 startUpdatingLocation메소드를 사용하여 로케이션 매니저를 시작한다.


- locationManager:didUpdateToLocation:fromLocation:

- locationManager:didFailWithError:


새 위치값을 사용할 때는 전자 이벤트가 발생한다. 위치값을 얻을 수 없을 경우, 후자 이벤트가 발생한다.

위치정보를 얻을 수 있는 경우, 그 위치의 위도, 경도등을 표시한다. 이는 CLLocation객체를 사용하여 처리한다. 이 객체의 horizontalAccuracy속성은 고도의 범위를 미터단위로 지정한다. 


- 지도에 표시하기

위치 좌표를 받았다. 이제는 그 위치를 지도상에 시각적으로 보여주기 위해  iOS에 기본내장된 MapKit API를 사용하여 구글맵에 표시해보자.

Interface Builder를 다시 실행하고 화면에 [지도보기]버튼을 추가하자.

그런 다음 Xocde에서 MapKit.framework프레임웍을 추가하고 GPSLocationViewController.h를 열고 아래 코드를 추가하자.

 #import <UIKit/UIKit.h>

#import <CoreLocation/CoreLocation.h>

#import <MapKit/MapKit.h>


@interface GPSLocationViewController : UIViewController <CLLocationManagerDelegate> {

IBOutlet UITextField *latiTextField;

IBOutlet UITextField *longiTextField;

IBOutlet UITextField *accuTextField;

CLLocationManager *lm;

MKMapView *mapView;

}


@property(nonatomic, retain) UITextField *latiTextField;

@property(nonatomic, retain) UITextField *longiTextField;

@property(nonatomic, retain) UITextField *accuTextField;


-(IBAction) ButtonViewMap:(id)sender;


@end


다 시 Interface Builder로 돌아와, control키를 누르고 버튼뷰를 클릭하여 [File's Owner]아이템을 드래그하여 ButtonViewMap를 선택한다. 다음은 GPSLocationViewController.m파일에 코드를 추가하자.

 -(IBAction)ButtonViewMap:(id)sender {

[self.view addSubview:mapView];

}


-(void) viewDidLoad {

lm = [[CLLocationManager alloc] init];

if([lm locationServicesEnabled]) {

lm.delegate = self;

lm.desiredAccuracy = kCLLocationAccuracyBest;

lm.distanceFilter = 1000.0f;

[lm startUpdatingLocation];

mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];

mapView.mapType = MKMapTypeHybrid;

}

}


-(void) locationManager: (CLLocationManager *) manager

  didUpdateToLocation: (CLLocation *) newLocation

  fromLocation: (CLLocation *) oldLocation {

NSString *lat = [[NSString alloc] initWithFormat:@"%g", newLocation.coordinate.latitude];

latiTextField.text = lat;

NSString *lng = [[NSString alloc] initWithFormat:@"%g", newLocation.coordinate.longitude];

longiTextField.text = lng;

NSString *acc = [[NSString alloc] initWithFormat:@"%g", newLocation.horizontalAccuracy];

accuTextField.text = acc;

[acc release];

[lat release];

[lng release];

MKCoordinateSpan span;

span.latitudeDelta =.005;

span.longitudeDelta = .005;

MKCoordinateRegion region;

region.center = newLocation.coordinate;

region.span = span;

[mapView setRegion:region animated:TRUE];

}


- (void)dealloc {

[mapView release];

[lm release];

[latiTextField release];

[longiTextField release];

[accuTextField release];

    [super dealloc];

}



위 코드는 기본적으로 다음 작업을 한다.


뷰 로드시, MKMapView 클래스의 인스턴스를 만들어 표시하는 맵형식(하이브리드)를 설정한다. 사용자가 지도보기 버튼을 누르면 현재 뷰에 mapView객체가 추가된다. 위치 정보가 업데이트될 때 mapView객체의  setRegion메소드를 사용하여 위치를 확대한다.


시물레이터는 항상 고정위치를 리턴하기 때문에 실제 기기를 테스트하지 않고는 정확한 테스트를 할 수 없다. 실제 기기에서 테스트할 때에는 distnaceFilter속성값을 작게 하여 짧은 거리도 체크해보기 바란다.


iOS SDK를 사용하여 간단하게 위치정보를 보여줄 수 있다.




출처 : http://lifehack.kr/90095713366