対象:
Swift4

ジオコーディング(Swift)

ある地点の緯度、及び経度から住所等の馴染みのある情報を得る逆ジオコーディング(リバースジオコーディング)はCLGeocoderを使えば簡単にできる。CLGeocoderを使うためには、まずCoreLocationをimportする必要がある。

import CoreLocation

それからCLGeocoderのインスタンスを生成し、逆ジオコーディングしたい位置情報をCLLocationにしてreverseGeocodeLocationメソッドに渡してリクエストするだけである。reverseGeocodeLocationメソッドに渡すハンドラには、逆ジオコーディングされた結果がCLPlacemarkの配列として返されるので、その最初の要素を参照すれば良い。

        let geocoder = CLGeocoder()
        // 千葉駅
        let location = CLLocation(latitude: 35.613203, longitude: 140.113544)
        geocoder.reverseGeocodeLocation(location) { (placemarks, error) in
            if let placemarks = placemarks {
                if let pm = placemarks.first {
                    print("name: \(pm.name ?? "")")
                    print("isoCountryCode: \(pm.isoCountryCode ?? "")")
                    print("country: \(pm.country ?? "")")
                    print("postalCode: \(pm.postalCode ?? "")")
                    print("administrativeArea: \(pm.administrativeArea ?? "")")
                    print("subAdministrativeArea: \(pm.subAdministrativeArea ?? "")")
                    print("locality: \(pm.locality ?? "")")
                    print("subLocality: \(pm.subLocality ?? "")")
                    print("thoroughfare: \(pm.thoroughfare ?? "")")
                    print("subThoroughfare: \(pm.subThoroughfare ?? "")")
                    if let region = pm.region {
                        print("region: \(region)")
                    }
                    if let timeZone = pm.timeZone {
                        print("timeZone: \(timeZone)")
                    }
                    print("inlandWater: \(pm.inlandWater ?? "")")
                    print("ocean: \(pm.ocean ?? "")")
                    if let areasOfInterest = pm.areasOfInterest {
                        print("areasOfInterest: \(areasOfInterest)")
                    }
                }
            }
        }

これを2018年1月にiOS 11で実行した結果が以下になる。いくつか関東のランドマーク的な場所を逆ジオコーディングしてみたが、国内だとnameには"〒"付きの郵便番号しか返ってこないようだ。

name: 〒260-0031
isoCountryCode: JP
country: 日本
postalCode: 260-0031
administrativeArea: 千葉県
subAdministrativeArea: 
locality: 千葉市中央区
subLocality: 新千葉
thoroughfare: 新千葉1丁目
subThoroughfare: 1
region: CLCircularRegion (identifier:'<+35.61320300,+140.11354400> radius 70.87', center:<+35.61320300,+140.11354400>, radius:70.87m)
timeZone: Asia/Tokyo (current)
inlandWater: 
ocean: 

しかし、同じ座標を2019年5月にiOS 12で逆ジオコーディングしてみたところ、以下のようにnameには郵便番号ではなく普通の住所が返ってきた。subThoroughfareも以前に実行した場合と変わっている。iOS 11の別端末でも同じように住所が返ってきたので、iOSが新しくなった結果というわけではないようだ。

name: 新千葉1丁目1-1
isoCountryCode: JP
country: 日本
postalCode: 260-0031
administrativeArea: 千葉県
subAdministrativeArea: 
locality: 千葉市中央区
subLocality: 新千葉
thoroughfare: 新千葉1丁目
subThoroughfare: 1-1
region: CLCircularRegion (identifier:'<+35.61320300,+140.11354400> radius 70.87', center:<+35.61320300,+140.11354400>, radius:70.87m)
timeZone: Asia/Tokyo (current)
inlandWater: 
ocean: 

更に、例えば東京ディズニーランド等では特定のnameが返ってくるようになった。2019年5月現在、他に上野恩賜公園、東京スカイツリータウン等が特定のnameを返すことが確認できた。結果から察するに、特定のregionの範囲内の座標であれば、それと関連付けられたnameが返ってくるのではないだろうか。

name: 東京ディズニーランド
isoCountryCode: JP
country: 日本
postalCode: 279-0031
administrativeArea: 千葉県
subAdministrativeArea: 
locality: 浦安市
subLocality: 舞浜
thoroughfare: 
subThoroughfare: 
region: CLCircularRegion (identifier:'<+35.63290299,+139.88039500> radius 141.74', center:<+35.63290299,+139.88039500>, radius:141.74m)
timeZone: Asia/Tokyo (current)
inlandWater: 
ocean: 
areasOfInterest: ["東京ディズニーランド"]

因みに、iOS 11以降はreverseGeocodeLocationメソッドでLocaleを指定できるようになったので、"en_US"を指定してApple Park辺りの座標を逆ジオコーディングすると、以下のような結果が得られた。nameには"Apple Park"が返ってきている。

        // Apple Park
        let location = CLLocation(latitude: 37.334902, longitude: -122.008872)
        // Localeでen_USを指定
        geocoder.reverseGeocodeLocation(location, preferredLocale: Locale(identifier: "en_US")) { (placemarks, error) in
            // 処理は同じ
        }
name: Apple Park
isoCountryCode: US
country: United States
postalCode: 95014
administrativeArea: CA
subAdministrativeArea: Santa Clara
locality: Cupertino
subLocality: Pruneridge Tantau
thoroughfare: 
subThoroughfare: 
region: CLCircularRegion (identifier:'<+37.33490199,-122.00887200> radius 141.73', center:<+37.33490199,-122.00887200>, radius:141.73m)
timeZone: America/Los_Angeles (fixed)
inlandWater: 
ocean: 
areasOfInterest: ["Apple Park"]

住所からその地点の緯度、及び経度の情報を求める正ジオコーディングもCLGeoCoderを使えば簡単にできる。ジオコーディングしたい住所情報をCLLocationにしてgeocodeAddressStringメソッドに渡してリクエストするだけである。geocodeAddressStringメソッドに渡すハンドラには、ジオコーディングされた結果がCLPlacemarkの配列として返されるので、その要素を参照すれば良い。

ただし、正ジオコーディングの場合、住所情報から解決される座標が1つとは限らないことに注意する必要がある。geocodeAddressStringメソッドは、住所以外に例えば"〒260-0031"のような郵便番号、"千葉駅"等もジオコーディングできるようだ。

        let geocoder = CLGeocoder()
        // 千葉駅
        let place = "新千葉1丁目1-1"
        geocoder.geocodeAddressString(place) { (placemarks, error) in
            if let placemarks = placemarks {
                print("placemarks.count: \(placemarks.count)")
                for pm in placemarks {
                    if let location = pm.location {
                        print("latitude: \(location.coordinate.latitude)")
                        print("longitude: \(location.coordinate.longitude)")
                    }
                }
            }
        }
placemarks.count: 1
latitude: 35.6128988
longitude: 140.1136959
(2018/01/28)
() ジオコーディング結果の最新情報、正ジオコーディング情報追記。

新着情報
【オープンソースソフトウェア環境構築】Visual StudioでOpenCVのビルド
【オープンソースソフトウェア環境構築】OpenCVで画像を表示
【iOS Objective-C, Swift Tips】ファイルアップロード(Swift)

Copyright© 2004-2019 モバイル開発系(K) All rights reserved.
[Home]