CoreLocation - [4] 緯度経度から住所情報を得る - MKReverseGeocoder

2010年10月14日木曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

[前回] Cocoaの日々: CoreLocation - [3] MKMapView の初期表示設定

今回は CLLocationManager から取得した緯度経度から住所情報を取得してみる。


MKReverseGeocoder


緯度経度から住所情報(文字列)を取得するには MKReverseGeocoder を使う。

使い方は簡単で緯度経度を引数としてインスタンスを生成し -start を投げるだけ。住所情報が取得できると MKReverseGeocoderDelegate で定義されたメソッドが呼び出される。
MKReverseGeocoder* reverseGeocoder = [[MKReverseGeocoder alloc] 
        initWithCoordinate:location.coordinate];
reverseGeocoder.delegate = self;
[reverseGeocoder start];
  :

- (void)reverseGeocoder:(MKReverseGeocoder*)geocoder
 didFindPlacemark:(MKPlacemark*)placemark {
    // 住所情報取得が成功した場合
}  

- (void) reverseGeocoder:(MKReverseGeocoder *)geocoder
 didFailWithError:(NSError*) error {  
    // 住所情報取得が失敗した場合
}


サンプル実装


前回までのプログラムに組み込んでみる。現在位置を表示する時にその緯度経度から住所情報を取得し表示するようにした。またピン(MKAnnotation実装クラス)に住所情報をもたせ、ピンをタップした時に吹き出しで表示するようにしてみた。

まず住所取得箇所。前回のピン表示メソッドの最後に MKReverseGeocoder の処理を追加する。
- (void)setPinToCoordinate:(CLLocation*)location
{
 // add annotation
 SimpleAnnotation* annotation = [[[SimpleAnnotation alloc] init] autorelease];
 annotation.location = location;
 [self.mapView addAnnotation:annotation];

 [self setAnnotation:annotation
     forCoordinate:location.coordinate];  // ...(*1)

 // setup default span
 MKCoordinateSpan span;
 if (self.mapView.region.span.latitudeDelta > 100) {
  span = MKCoordinateSpanMake(0.005, 0.005);
 } else {
  span = self.mapView.region.span;
 }

 // set the map view to location
 CLLocationCoordinate2D centerCoordinate = location.coordinate;
 MKCoordinateRegion coordinateRegion =
  MKCoordinateRegionMake(centerCoordinate, span);
 [self.mapView setRegion:coordinateRegion animated:YES]; 
 
 MKReverseGeocoder* reverseGeocoder = [[MKReverseGeocoder alloc]
                initWithCoordinate:location.coordinate];
 reverseGeocoder.delegate = self;
 [reverseGeocoder start];
}
SimpleAnnotaion を緯度経度(CLLocationCoordinate2D)をキーにして辞書へとっておく(*1の箇所)。これは MKReverseGeocoder の住所取得が終わった時に住所情報を格納するため。住所取得処理は次の通り。
#pragma mark -
#pragma mark MKReverseGeocoderDelegate
- (void)reverseGeocoder:(MKReverseGeocoder*)geocoder
 didFindPlacemark:(MKPlacemark*)placemark {
 self.label.text = placemark.title;

 SimpleAnnotation* annotation =
  [self annotationForCoordinate:geocoder.coordinate];
 annotation.title = placemark.title;

}  

- (void) reverseGeocoder:(MKReverseGeocoder *)geocoder
 didFailWithError:(NSError*) error {  

 self.label.text = [error description];

 SimpleAnnotation* annotation =
 [self annotationForCoordinate:geocoder.coordinate];
 annotation.title = [error description];
}
成功(あるいは失敗)したら取っておいた SimpleAnnotation を coodinate(緯度経度)をキーにして取り出し、titleへ住所情報を格納している。
SimpleAnnotation には titleプロパティを追加してある。
@interface SimpleAnnotation : NSObject {

 CLLocation* location_;
 NSString* title_;
}
@property (nonatomic, copy) CLLocation* location;
@property (nonatomic, retain) NSString* title;

@end
SimpleAnnotation の管理は NSMutableDictionaryで行う。出し入れのメソッドは次の通り。
#pragma mark -
#pragma mark Management for annotationDictionary
- (void)setAnnotation:(SimpleAnnotation*)annotation
 forCoordinate:(CLLocationCoordinate2D)coordinate
{
 NSValue* coordinateValue = [NSValue value:&coordinate
         withObjCType:@encode(CLLocationCoordinate2D)];
 [self.annotationDictionary setObject:annotation
          forKey:coordinateValue];
}

- (SimpleAnnotation*)annotationForCoordinate:(CLLocationCoordinate2D)coordinate
{
 NSValue* coordinateValue = [NSValue value:&coordinate
         withObjCType:@encode(CLLocationCoordinate2D)];
 SimpleAnnotation* annotation = [self.annotationDictionary objectForKey:coordinateValue];
 [self.annotationDictionary removeObjectForKey:coordinateValue];
 
 return annotation;
}
辞書のキーとなる CLLocationCoordinate2D はCの構造体はそのままでは入れられないので一旦 NSValue へ詰め替えてから使用している。


サンプル実行


ピンをタップすると住所情報が表示される。

ソースコード


GitHub からどうぞ。
CoreLocationSample at 2010-10-14 from xcatsan's iOS-Sample-Code - GitHub


備考


MKReverseGeocoder は GoogleのAPIを利用しているらしいが、取得に失敗することが多いらしく評判があまりよくない。

琴線探査: MKReverseGeocoderは大きい道路上を指定すると常にエラーか?

MKReverseGeocoder not working? « Welcome to Mobile World !!!

PBRequesterErrorDomain errors with reverse geocoding - iPhone Dev SDK Forum

MKReverseGeocoderは使わない方がいいみたい « wigglin’ bloggin’

上記ブログより抜粋。
良い時で1割くらい、悪いときは百発百中でこのエラーが発生します。
実際、少し試しただけでも数回に1回ぐらいの頻度で取得に失敗した。あるケースでは郵便番号だけが帰ってきたこともあった。
GoogleMapsのREST APIを使ったらうまくいったとの報告があったので、同じ事を試してみたらアッサリと解決したのでした。


実際サンプル作成中にも下記のエラーが発生した。
/SourceCache/GoogleMobileMaps_Sim/GoogleMobileMaps-257/
  googlenav/mac/Loader.mm:231 server returned error: 503


このあたり本格的な利用に際しては GoogleMapsのREST APIの利用も検討した方が良いかもしれない。あるいは何回かリトライしてみるとか?


参考情報


MKReverseGeocoder Class Reference
リファレンス

[iPhone] MapKit でリバースジオコーディング、緯度経度から住所を取得 | Sun Limited Mt.
MKReverseGeocoder の使い方で参考になった。

NSArrayにNSValueでC構造体を格納する - stoikheiaの日記
CLLocationCoordinate2D を NSMutableDictionary へ格納するのに参考になった。

琴線探査: MKReverseGeocoderでより精度の高い住所情報はMKPlacemark.addressDictionaryにあった!

Responses

Leave a Response

人気の投稿(過去 30日間)