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

맵뷰(MapView) 3장 - CLLocation을 이용해 MapView에 현재위치 표시하기

by 백룡화검 2012. 2. 9.

2장에 이어 .m 마저 해봅시다.


 
- (id) init {
    self = [super init];
    if (self != nil) {
        myMapView = [[MKMapView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
        [myMapView setShowsUserLocation:YES];
        [myMapView setMapType:MKMapTypeStandard];
        [self.view insertSubview:myMapView atIndex:0];
    }
    return self;
}


- (id) init {}

초기화 함수입니다. 이안에 코딩할예정입니다.

init나 ViewDidLoad, viewDidAppear중 어디에 코딩을 할지는 어플리케이션의 용도에 따라 달라지게 됩니다.


self = [super init];

self로 초기화 시켰습니다.


if (self != nil)

초기화가 제대로 됐을때만 작동을 하게 해줍니다.


myMapView = [[MKMapView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];

앞에서 선언한 myMapView를 MKMapView형식으로 초기화 시키고 메모리올리는데 프레임을 지정해줬습니다.

CGRectMake(<CGFloat x>, <CGFloat y>, <CGFloat width>, <CGFloat height>)의 형식을 요구합니다.

화면의 x/y 좌표를 기준으로 width/height만큼 그려지게 됩니다. OpenGL을 쓸경우 x/y좌표의 기준점이 바뀝니다.

Float 형식이기 때문에 소숫점까지 조절가능합니다만 (0, 0, 320, 480) 처럼 생략해도 됩니다.

initWithFrame는 CGRectMake이외에도 다양한 옵션을 가지고 있으니 레퍼런스를 한번쯤 봐두시는것이 좋습니다.


[myMapView setShowsUserLocation:YES];

현재의 내위치를 화면에 표시해줄것인지 YES/NO로 설정가능합니다.

YES로 설정을 하면 지도에 파란점으로 내위치가 표시됩니다.


[myMapView setMapType:MKMapTypeStandard];

지도의 타입을 설정했습니다.

기본 지도형식인 MKMapTypeStandard 항공지도인 MKMapTypeSatellite, 두가지를 동시에 보여주는 MKMapTypeHybrid 타입을 지원합니다.


[self.view insertSubview:myMapView atIndex:0];
이제 만들어진 myMapView를 뷰컨트롤러에 추가해줘야 합니다.

뒤에 붙는 atIndex의 숫자로 여러종류의 뷰가 사용될경우 위아래를 결정해줄수 있습니다.


이제 시뮬레이션을 돌리면 지도가 떠있을겁니다.


 
읭?!

내위치가 보이긴 하는데 미국 캘리포니아에 있다고 나오는군요.

시뮬레이션은 말그대로 GPS를 가지고 있지는 않아서 캘리포니아에있는 애플본사를 표시하도록 되어있습니다. =(


자 그럼 디바이스로 변경해보겠습니다.

        


이제 아이폰도 연결을 하고 돌려보겠습니다.

  


"testLocation"에서 현재 위치 정보를 사용하고 합니다."라는 알람이 뜹니다. 승인을 누르면 오른쪽 화면처럼 자신의 위치가 잡힙니다.

좀 엄하죠? 대한민국 전체도 모자라 일본도 보이네요 =) 이제 코어로케이션이 필요한 시점입니다. 다시 .m으로 갑니다.


 
- (id) init {
    self = [super init];
    if (self != nil) {
        myMapView = [[MKMapView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)
        [myMapView setShowsUserLocation:YES];
        [myMapView setMapType:MKMapTypeStandard];
        [myMapView.userLocation setTitle:@"Here I am"];
        [self.view insertSubview:myMapView atIndex:0];
       
        locationManager = [[CLLocationManager alloc] init];
        locationManager.delegate = self;
        locationManager.desiredAccuracy = kCLLocationAccuracyBest;
        locationManager.distanceFilter = kCLDistanceFilterNone;
        [locationManager startUpdatingLocation];
    }
    return self;
}

- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation {

    if (startPoint == nil) {
        self.startPoint = newLocation;
    }
    MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(newLocation.coordinate, 1500, 1500);
    [myMapView setRegion:viewRegion animated:YES];
    [locationManager stopUpdatingLocation];
}


으허허허헝 색칠하는게 더 어렵네요 ;ㅅ;

[myMapView.userLocation setTitle:@"Here I am"];

한줄 추가해줬습니다. 내 위치에 표시되는 파란점을 터치하면 나타나는 팝업메시지 입니다.


locationManager = [[CLLocationManager alloc] init];

로 케이션 매니저의 인스턴스를 생성하지만 폴링을 시작하고 위치정보를 갱신하지 않는상태. 폴링을 시작하려면 먼저 델리게이트 객체를 만들고, 델리게이트 객체를 로케이션 매니저에 할당해야합니다.. 로케이션 매니저는 위치정보를 수신하면 델리게이트 메서드를 호출하는데, 위치정보를 결정하려면 어느정도의 시간이 필요하며 오래 걸릴때에는 몇 초씩 걸릴 때도 있습니다. 델리게이트로 사용되는 객체는 반드시 CLLocationDelegate프로토콜을 따라야 합니다.


locationManager.delegate = self;

델리게이트를 설정했습니다.


locationManager.desiredAccuracy = kCLLocationAccuracyBest;

정 밀도를 설정합니다. 정밀도가 높으면 전력소모가 많아집니다.CLLocationAccuracy는 double형 입니다. 미터 단위를 사용하며, kCLLocationAccuracyTenMeters, kCLLocationAccuracyHundredMeters, kCLLocationAccuracyKilometers,

kCLLocationAccuracyThreeKilometers 등이 있습니다. 상황에 맞게 설정하세요.


locationManager.distanceFilter = kCLDistanceFilterNone;

로케이션 매니저는 기본적으로 위치가 변경되면 델리게이트에 통보합니다. 이 디스턴스 필터를 설정하면 설정한 거리 이상 이동하였을때만 호출하게 됩니다.

이값역시 미터단위를 사용합니다. 우리는 디스턴스 필터를 꺼줍니다. ex) locationManager.distnceFilter = 100.0f


[locationManager startUpdatingLocation];

이제 로케이션 매니저를 동작시키면 locationManager:didUpdateToLocation:fromLocation:매서드가 호출됩니다.


- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation {

    if (startPoint == nil) {
        self.startPoint = newLocation;
    }
    MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(newLocation.coordinate, 1500, 1500);
    [myMapView setRegion:viewRegion animated:YES];
    [locationManager stopUpdatingLocation];
}


locationManager:didUpdateToLocation:fromLocation:매서드는 3개의 인자를 갖고 있으며, 첫째인자는 델리게이트 메서드를 호출한 로케이션 매니저입니다.

두번째와 세번째 인자는 CLLocation 형식의 객체이며 두번째 인자는 아이폰의 현재의 위치를 가지고 있고 세번째 인자는 이전 위치를 가지고 있으며, 처음 메서드가 호출될때는 nil값을 가지고 있습니다.


if (startPoint == nil) {
       self.startPoint = newLocation;
}

처음 호출될때의 위치정보를 startPoint에 저장합니다.


MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(newLocation.coordinate, 1500, 1500);

Region 을 하나 생성해줍니다. coordinate는 위도(latitude)와 경도(longitude)로 구성되어있습니다. 현재의 위치(newLocation.coordinate)와 현재 위치를 기준으로 위도/경도 1500m의 거리를 viewRegion에 담습니다.


[myMapView setRegion:viewRegion animated:YES];

위에서 만든 장소를 myMapView에 셋팅합니다. 뒤에 붙는 animated는 YES/NO값을 가지며, 위에서 처음에 봤던 한국 전체 지도에서 현재 셋팅한 위치까지 확대되는 에니매이션을 설정하는 값입니다.


[locationManager stopUpdatingLocation];

현재 위치를 보여줬으니 로케이션 매니저를 멈춥니다. 로케이션 매니저로 계속 위치를 추적하게 되면 전력소모가 제법 되기 때문에 필요한 부분에서만

스타트 시키고 무조건 꺼주게 설정했습니다.


이제 디바이스로 실행시키면 현재 아이폰의 위치가 보일겁니다.!