サンプルコードを用意
Swift + iOS で リバースジオコーディングして取得した CLPlacemark の中身がどういうデータになっているか調べるサンプルコードを書いてみた。
今回の環境: Xcode 7.3.1 + iPhone 6 実機 + iOS 9.3.5
Xcode のメニューから [File] → [New] → [Project] → [iOS] → [Application] → [Single View Application] で新しいプロジェクトを作成して、以下のコードを ViewController.swift に貼り付けて、実行すればOK (コピペでお手軽に)。
import UIKit
import MapKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
ViewController.invoke()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
private static func invoke() {
let locations = [
["0,0", "0", "0"],
["35,135", "35", "135"],
["名古屋駅", "35.1707", "136.8826"],
["名古屋城", "35.1856", "136.8991"],
["木曽川", "35.2564", "136.6913"],
["琵琶湖", "35.2676", "136.0937"],
["インド洋", "-22.3918", "80.0957"],
["スペリオル湖", "47.8247", "-87.3552"],
["エッフェル塔", "48.858244", "2.294598"],
]
for location in locations {
let latlon = CLLocation(latitude: Double(location[1])!, longitude: Double(location[2])!)
reverseGeocode(location[0], location: latlon, completion: printLocation)
}
}
private static func reverseGeocode(name: String, location: CLLocation, completion:(name: String, location: CLLocation, placemarks: [CLPlacemark]?, error: NSError?) -> Void) {
let geocorder = CLGeocoder()
geocorder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
completion(name: name, location: location, placemarks: placemarks, error: error)
})
}
private static func printLocation(name: String, location: CLLocation, placemarks: [CLPlacemark]?, error: NSError?) {
print("**********************************************************************")
print("[\(name)]")
print("latitude: \(location.coordinate.latitude)")
print("longitude: \(location.coordinate.longitude)")
if let ps = placemarks {
print("CLPlacemarks.count: \(ps.count)")
for p in ps {
print("CLPlacemark: [")
// The location object containing latitude and longitude information.
if p.location != nil {
print(" location: \(p.location!)")
}
// The name of the placemark.
if p.name != nil {
print(" name: \(p.name!)")
}
// A dictionary containing the Address Book keys and values for the placemark.
if let ad = p.addressDictionary {
print(" addressDictionary: [")
for k in ad.keys {
if let v = ad[k] {
print(" \(k): \(v) (\(v.dynamicType))")
if let array = v as? NSMutableArray {
print(" [")
for elem in array {
print(" \(elem)")
}
print(" ]")
}
}
}
print(" ]")
}
// The abbreviated country name.
if p.ISOcountryCode != nil {
print(" ISOcountryCode: \(p.ISOcountryCode!)")
}
// The name of the country associated with the placemark.
if p.country != nil {
print(" country: \(p.country!)")
}
// The postal code associated with the placemark.
if p.postalCode != nil {
print(" postalCode: \(p.postalCode!)")
}
// The state or province associated with the placemark.
if p.administrativeArea != nil {
print(" administrativeArea: \(p.administrativeArea!)")
}
// Additional administrative area information for the placemark.
if p.subAdministrativeArea != nil {
print(" subAdministrativeArea: \(p.subAdministrativeArea!)")
}
// The city associated with the placemark.
if p.locality != nil {
print(" locality: \(p.locality!)")
}
// Additional city-level information for the placemark.
if p.subLocality != nil {
print(" subLocality: \(p.subLocality!)")
}
// The street address associated with the placemark.
if p.thoroughfare != nil {
print(" thoroughfare: \(p.thoroughfare!)")
}
// Additional street-level information for the placemark.
if p.subThoroughfare != nil {
print(" subThoroughfare: \(p.subThoroughfare!)")
}
// The geographic region associated with the placemark.
if p.region != nil {
print(" region: \(p.region!)")
}
// The time zone associated with the placemark.
if p.timeZone != nil {
print(" timeZone: \(p.timeZone!)")
}
// The name of the inland water body associated with the placemark.
if p.inlandWater != nil {
print(" inlandWater: \(p.inlandWater!)")
}
// The name of the ocean associated with the placemark.
if p.ocean != nil {
print(" ocean: \(p.ocean!)")
}
// The relevant areas of interest associated with the placemark.
if p.areasOfInterest != nil {
print(" areasOfInterest: \(p.areasOfInterest!)")
}
print("]")
}
}
if let e = error {
print("Error: \(e)")
}
}
}
ref. CLPlacemark Class Reference
CLPlacemark の中身
サンプルコードで出力したデータをひとつずつ見ていく。
[0,0]
緯度0度、経度0度では、name プロパティが「北大西洋」で、 ocean プロパティも「北大西洋」。
[0,0]
latitude: 0.0
longitude: 0.0
CLPlacemarks.count: 1
CLPlacemark: [
location: <+30.70548840,-40.57543660> +/- 100.00m (speed -1.00 mps / course -1.00) @ 2016/08/28 12時30分16秒 日本標準時
name: 北大西洋
addressDictionary: [
FormattedAddressLines: (
"\U5317\U5927\U897f\U6d0b"
) (__NSArrayM)
[
北大西洋
]
Name: 北大西洋 (__NSCFString)
Ocean: 北大西洋 (__NSCFString)
]
region: CLCircularRegion (identifier:'<+31.73555050,-38.20364380> radius 5941202.70', center:<+31.73555050,-38.20364380>, radius:5941202.70m)
timeZone: GMT (GMT) offset 0
ocean: 北大西洋
]
[インド洋]
name プロパティが「インド洋」で、 ocean プロパティも「インド洋」。海の情報はシンプル。
**********************************************************************
[インド洋]
latitude: -22.3918
longitude: 80.0957
CLPlacemarks.count: 1
CLPlacemark: [
location: <-15.91310440,+79.25161300> +/- 100.00m (speed -1.00 mps / course -1.00) @ 2016/08/28 12時30分16秒 日本標準時
name: インド洋
addressDictionary: [
FormattedAddressLines: (
"\U30a4\U30f3\U30c9\U6d0b"
) (__NSArrayM)
[
インド洋
]
Name: インド洋 (__NSCFString)
Ocean: インド洋 (__NSCFString)
]
region: CLCircularRegion (identifier:'<-20.60060190,+83.44213305> radius 6918767.42', center:<-20.60060190,+83.44213305>, radius:6918767.42m)
timeZone: GMT+0500 (GMT+5) offset 18000
ocean: インド洋
]
[35,135]
住所情報が administrativeArea, locality, subLocality, thoroughfare プロパティにセットされている。これを単純につなげてしまうと「兵庫県 西脇市 上比延町 上比延町」と「上比延町」が重複してしまう。データとしてとても扱いづらい。
addressDictionary プロパティが持つ FormattedAddressLines には配列で「兵庫県西脇市」「上比延町」が入っているので、これをつなげたほうが綺麗かもしれない。
**********************************************************************
[35,135]
latitude: 35.0
longitude: 135.0
CLPlacemarks.count: 1
CLPlacemark: [
location: <+35.00101560,+134.99704500> +/- 100.00m (speed -1.00 mps / course -1.00) @ 2016/08/28 12時30分16秒 日本標準時
name: 上比延町
addressDictionary: [
SubLocality: 上比延町 (__NSCFString)
Street: 上比延町 (__NSCFString)
State: 兵庫県 (__NSCFString)
CountryCode: JP (NSTaggedPointerString)
Thoroughfare: 上比延町 (__NSCFString)
Name: 上比延町 (__NSCFString)
Country: 日本 (__NSCFString)
FormattedAddressLines: (
"\U5175\U5eab\U770c\U897f\U8107\U5e02",
"\U4e0a\U6bd4\U5ef6\U753a"
) (__NSArrayM)
[
兵庫県西脇市
上比延町
]
City: 西脇市 (__NSCFString)
]
ISOcountryCode: JP
country: 日本
administrativeArea: 兵庫県
locality: 西脇市
subLocality: 上比延町
thoroughfare: 上比延町
region: CLCircularRegion (identifier:'<+35.00926235,+135.00460170> radius 1563.14', center:<+35.00926235,+135.00460170>, radius:1563.14m)
timeZone: Asia/Tokyo (JST) offset 32400
]
[名古屋駅]
住所が入っているプロパティは、administrativeArea: 愛知県, locality: 名古屋市中村区, subLocality: 名駅, thoroughfare: 名駅1丁目, subThoroughfare: 1番4号 と数が多い。
FormattedAddressLines をつなげると「〒450-0002 愛知県名古屋市中村区 名駅1丁目1番4号」と郵便番号も入ってしまうので、住所文字列として使うには郵便番号は削除したい。
**********************************************************************
[名古屋駅]
latitude: 35.1707
longitude: 136.8826
CLPlacemarks.count: 1
CLPlacemark: [
location: <+35.17059000,+136.88300600> +/- 100.00m (speed -1.00 mps / course -1.00) @ 2016/08/28 12時30分16秒 日本標準時
name: 名駅1丁目1番4号
addressDictionary: [
SubLocality: 名駅 (__NSCFString)
Street: 名駅1丁目1番4号 (__NSCFString)
State: 愛知県 (__NSCFString)
SubThoroughfare: 1番4号 (__NSCFString)
CountryCode: JP (NSTaggedPointerString)
ZIP: 450-0002 (NSTaggedPointerString)
Thoroughfare: 名駅1丁目 (__NSCFString)
Name: 名駅1丁目1番4号 (__NSCFString)
Country: 日本 (__NSCFString)
FormattedAddressLines: (
"\U3012450-0002",
"\U611b\U77e5\U770c\U540d\U53e4\U5c4b\U5e02\U4e2d\U6751\U533a",
"\U540d\U99c51\U4e01\U76ee1\U756a4\U53f7"
) (__NSArrayM)
[
〒450-0002
愛知県名古屋市中村区
名駅1丁目1番4号
]
City: 名古屋市中村区 (__NSCFString)
]
ISOcountryCode: JP
country: 日本
postalCode: 450-0002
administrativeArea: 愛知県
locality: 名古屋市中村区
subLocality: 名駅
thoroughfare: 名駅1丁目
subThoroughfare: 1番4号
region: CLCircularRegion (identifier:'<+35.17059000,+136.88300600> radius 70.87', center:<+35.17059000,+136.88300600>, radius:70.87m)
timeZone: Asia/Tokyo (JST) offset 32400
]
[スペリオル湖]
アメリカの五大湖のひとつスペリオル湖。inlandWater プロパティに「スペリオル湖」がセットされている。inland water (陸水) は、 陸地に囲まれた水場のことらしい。
FormattedAddressLines を単純につなげると「スペリオル湖 MI アメリカ合衆国」となってしまう。MIはミシガン州の略称。
**********************************************************************
[スペリオル湖]
latitude: 47.8247
longitude: -87.3552
CLPlacemarks.count: 1
CLPlacemark: [
location: <+47.37232100,-86.99389700> +/- 100.00m (speed -1.00 mps / course -1.00) @ 2016/08/28 12時30分16秒 日本標準時
name: スペリオル湖
addressDictionary: [
SubAdministrativeArea: キウィーナー (__NSCFString)
State: MI (NSTaggedPointerString)
CountryCode: US (NSTaggedPointerString)
Country: アメリカ合衆国 (__NSCFString)
Name: スペリオル湖 (__NSCFString)
FormattedAddressLines: (
"\U30b9\U30da\U30ea\U30aa\U30eb\U6e56",
MI,
"\U30a2\U30e1\U30ea\U30ab\U5408\U8846\U56fd"
) (__NSArrayM)
[
スペリオル湖
MI
アメリカ合衆国
]
InlandWater: スペリオル湖 (__NSCFString)
]
ISOcountryCode: US
country: アメリカ合衆国
administrativeArea: MI
subAdministrativeArea: キウィーナー
region: CLCircularRegion (identifier:'<+47.37232100,-87.82621875> radius 223107.40', center:<+47.37232100,-87.82621875>, radius:223107.40m)
timeZone: America/Detroit (GMT-4) offset -14400 (Daylight)
inlandWater: スペリオル湖
]
[琵琶湖]
日本の河川や湖には inlandWater プロパティはセットされないのかもしれない。残念。
**********************************************************************
[琵琶湖]
latitude: 35.2676
longitude: 136.0937
CLPlacemarks.count: 1
CLPlacemark: [
location: <+35.46149990,+135.95648940> +/- 100.00m (speed -1.00 mps / course -1.00) @ 2016/08/28 12時30分16秒 日本標準時
name: 高島市
addressDictionary: [
City: 高島市 (__NSCFString)
CountryCode: JP (NSTaggedPointerString)
Name: 高島市 (__NSCFString)
State: 滋賀県 (__NSCFString)
FormattedAddressLines: (
"\U6ecb\U8cc0\U770c\U9ad8\U5cf6\U5e02"
) (__NSArrayM)
[
滋賀県高島市
]
Country: 日本 (__NSCFString)
]
ISOcountryCode: JP
country: 日本
administrativeArea: 滋賀県
locality: 高島市
region: CLCircularRegion (identifier:'<+35.38725930,+135.97175850> radius 25441.65', center:<+35.38725930,+135.97175850>, radius:25441.65m)
timeZone: Asia/Tokyo (JST) offset 32400
]
[木曽川]
残念ながら、川らしい情報は入っていない。
**********************************************************************
[木曽川]
latitude: 35.2564
longitude: 136.6913
CLPlacemarks.count: 1
CLPlacemark: [
location: <+35.25800180,+136.69000420> +/- 100.00m (speed -1.00 mps / course -1.00) @ 2016/08/28 12時30分16秒 日本標準時
name: 桑原町前野
addressDictionary: [
SubLocality: 桑原町 (__NSCFString)
Street: 桑原町前野 (__NSCFString)
State: 岐阜県 (__NSCFString)
CountryCode: JP (NSTaggedPointerString)
Thoroughfare: 桑原町前野 (__NSCFString)
Name: 桑原町前野 (__NSCFString)
Country: 日本 (__NSCFString)
FormattedAddressLines: (
"\U5c90\U961c\U770c\U7fbd\U5cf6\U5e02",
"\U6851\U539f\U753a\U524d\U91ce"
) (__NSArrayM)
[
岐阜県羽島市
桑原町前野
]
City: 羽島市 (__NSCFString)
]
ISOcountryCode: JP
country: 日本
administrativeArea: 岐町前野
]
City: 羽島市 (__NSCFString)
]
ISOcountryCode: JP
country: 日本
administrativeArea: 岐\351阜県
locality: 羽島市
subLocality: 桑原町
thoroughfare: 桑原町前野
region: CLCircularRegion (identifier:'<+35.25605055,+136.68932470> radius 1011.70', center:<+35.25605055,+136.68932470>, radius:1011.70m)
timeZone: Asia/Tokyo (JST) offset 32400
]
[エッフェル塔]
フランスの首都パリにあるランドマーク。areasOfInterest に「["エッフェル塔", "シャン・ド・マルス公園"]」という文字列の配列型データがセットされている。
FormattedAddressLines も他のプロパティも翻訳が中途半端に見える。住所情報を使うのは難しそうだ。
**********************************************************************
[エッフェル塔]
latitude: 48.858244
longitude: 2.294598
CLPlacemarks.count: 1
CLPlacemark: [
location: <+48.85855330,+2.29467190> +/- 100.00m (speed -1.00 mps / course -1.00) @ 2016/08/28 12時30分16秒 日本標準時
name: エッフェル塔
addressDictionary: [
SubLocality: Tour Eiffel-Champs de Mars (__NSCFString)
SubAdministrativeArea: パリ (__NSCFString)
State: イル=ド=フランス (__NSCFString)
Street: Avenue Anatole France (__NSCFString)
CountryCode: FR (NSTaggedPointerString)
ZIP: 75007 (NSTaggedPointerString)
Thoroughfare: Avenue Anatole France (__NSCFString)
Name: エッフェル塔 (__NSCFString)
Country: フランス (__NSCFString)
FormattedAddressLines: (
"\U30a8\U30c3\U30d5\U30a7\U30eb\U5854",
"Avenue Anatole France",
"75007 \U30d1\U30ea",
"\U30d5\U30e9\U30f3\U30b9"
) (__NSArrayM)
[
エッフェル塔
Avenue Anatole France
75007 パリ
フランス
]
City: パリ (__NSCFString)
]
ISOcountryCode: FR
country: フランス
postalCode: 75007
administrativeArea: イル=ド=フランス
subAdministrativeArea: パリ
locality: パリ
subLocality: Tour Eiffel-Champs de Mars
thoroughfare: Avenue Anatole France
region: CLCircularRegion (identifier:'<+48.85855329,+2.29467190> radius 141.63', center:<+48.85855329,+2.29467190>, radius:141.63m)
timeZone: Europe/Paris (GMT+2) offset 7200 (Daylight)
areasOfInterest: ["エッフェル塔", "シャン・ド・マルス公園"]
]
[名古屋城]
ランドマークらしい情報はセットされていない。
**********************************************************************
[名古屋城]
latitude: 35.1856
longitude: 136.8991
CLPlacemarks.count: 1
CLPlacemark: [
location: <+35.18519580,+136.89884690> +/- 100.00m (speed -1.00 mps / course -1.00) @ 2016/08/28 12時30分16秒 日本標準時
name: 本丸
addressDictionary: [
SubLocality: 本丸 (__NSCFString)
Street: 本丸 (__NSCFString)
State: 愛知県 (__NSCFString)
CountryCode: JP (NSTaggedPointerString)
Thoroughfare: 本丸 (__NSCFString)
Name: 本丸 (__NSCFString)
Country: 日本 (__NSCFString)
FormattedAddressLines: (
"\U611b\U77e5\U770c\U540d\U53e4\U5c4b\U5e02\U4e2d\U533a",
"\U672c\U4e38"
) (__NSArrayM)
[
愛知県名古屋市中区
本丸
]
City: 名古屋市中区 (__NSCFString)
]
ISOcountryCode: JP
country: 日本
administrativeArea: 愛知県
locality: 名古屋市中区
subLocality: 本丸
thoroughfare: 本丸
region: CLCircularRegion (identifier:'<+35.18519595,+136.89888935> radius 386.14', center:<+35.18519595,+136.89888935>, radius:386.14m)
timeZone: Asia/Tokyo (JST) offset 32400
]
参考資料
CLPlacemark の公式リファレンス。
⇒ location - CLPlacemark Class Reference
リバースジオコーディングが返すデータについて、日本語環境と英語環境の比較表が載っている。
⇒ UQ Times 開発の記録: CoreLocationサンプル3 - ジオコーディング
tags: swift
Posted by NI-Lab. (@nilab)