2010年3月21日日曜日

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

先日MKReverseGeocoderの精度は決して高くなさそうだと書いたが、それは間違いだった。
琴線探査: iPhoneアプリでのより高精度な逆ジオコーディングを求めて・・・

より精度の高い住所情報は、MKPlacemark.addressDictionary.FormattedAddressLinesから取得できるとわかった。

/**
 *
 * MKPlacemark.addressDictionaryから取得するFormattedAddressLinesを
 * 一行の文字列として返す
 *
 */
- (NSString *)getFormattedAddressLineFromPlacemark:(MKPlacemark *)pm {

 //最終的な住所文字列
 NSString *line = @"";
 
 //まずはMKPlacemarkのプロパティーを出力
 NSLog(@"MKPlacemark出力 thoroughfare=%@ subThoroughfare=%@ locality=%@ subLocality=%@ administrativeArea=%@ subAdministrativeArea=%@ postalCode=%@ country=%@ countryCode=%@",
    pm.thoroughfare, pm.subThoroughfare, pm.locality, pm.subLocality,
    pm.administrativeArea, pm.subAdministrativeArea, pm.postalCode,
    pm.country, pm.countryCode);
 
 //より詳細な住所はMKPlacemark.addressDictionaryに隠されている
 NSDictionary *dict = pm.addressDictionary;
 //for (id key in dict) {
 // NSLog(@"key=%@ value=%@", key, [dict objectForKey:key]);
 //}
 
 //FormattedAddressLinesを一行の文字列に連結
 //ドキュメントには明記されているところが見当たらないがFormattedAddressLinesは配列で返って来るらしい
 NSArray *lines = [dict valueForKey:@"FormattedAddressLines"];
 for (int i = 0; i < lines.count; i++) {
  line = [line stringByAppendingFormat:@"%@ ", [lines objectAtIndex:i]];
 }
 
 //上で出力したプロパティーと比較して、こちらにだけ存在する情報があるとわかる
 //(郵便番号や住所の末尾「-3」)
 NSLog(@"%@:FormattedAddressLines出力 lines.count=%d", line, lines.count);

 return line;
 
}
例えば、位置を国会議事堂として逆ジオコーディングを行い、その結果のMKPlacemarkをこのメソッドを使って出力するとこうなる。
MKPlacemark出力 thoroughfare=1丁目 subThoroughfare=7 locality=千代田区 subLocality=永田町 administrativeArea=東京都 subAdministrativeArea=(null) postalCode=(null) country=日本 countryCode=JP
日本 〒100-0014 東京都千代田区永田町1丁目7−1 :FormattedAddressLines出力 lines.count=2
MKPlacemarkのプロパティーの出力をFormattedAddressLines出力にできるだけ似せて書くとこうなる。
日本 東京都千代田区永田町1丁目7
つまり、FormattedAddressLines出力に比べて郵便番号「〒100-0014」と番地レベルの「−1」の部分の情報が抜け落ちていることがわかる。 上のコードではコメントされているが、addressDictionaryの中身を出力してみるとこうなる。
key=Street value=1丁目 7
key=State value=東京都
key=CountryCode value=JP
key=FormattedAddressLines value=(
    "¥U65e5¥U672c",
    "¥U3012100-0014 ¥U6771¥U4eac¥U90fd¥U5343¥U4ee3¥U7530¥U533a¥U6c38¥U7530¥U753¥Uff11¥U4e01¥U76ee¥Uff17¥U2212¥Uff11"
)
key=City value=千代田区
key=SubThoroughfare value=7
key=Country value=日本
key=Thoroughfare value=1丁目
key=SubLocality value=永田町
どうやらMKPlacemarkのプロパティーはaddressDictionaryの中身を適当に展開したものが入っているようだ。

日本中の色々な場所を出力させてみたが、国内の場合はMKPlacemarkの情報とFormattedAddressLinesの情報は違いはあるものの、大体似たような文字列が使われているので、フィルタリングすればMKPlacemarkのプロパティーで足りていない部分を判断して取得することができるだろう。

海外を出力させてみたところ、そもそも情報がなかったり必ずしもMKPlacemarkのプロパティーと対応していなかったり・・・と相当苦労しそうだ。