9
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Swift/iOS】CoreLocationで取得した位置情報を住所に変換する

Last updated at Posted at 2019-11-26

概要

下記の記事で説明した位置情報から自然な住所の表記に変換する方法について説明します。
【Swift/iOS】CoreLocationで緯度・経度を取得して位置情報を表示する

位置情報を取得した場所によって地名として取得される情報の粒度が異なるため、地名をつなげるだけでは自然な住所表記にならない場合があります。
具体例としては、下記の実行結果をご覧ください。

確認バージョン

Xcode 11.2.1
Swift 5.1.2
iOS 13.2.2

要件

  1. 地名が丁目や番地まで取得できる場所では丁目や番地までの住所を出力
  2. 地名が「〜通り」や「〜道路」などの場合には丁目なしの住所を出力
  3. 「〜通り」や「〜道路」は住所に含めない

結論

下記のように実装すると要件を満たす住所が出力されました。

//位置情報
let administrativeArea = placemark.administrativeArea == nil ? "" : placemark.administrativeArea!
let locality = placemark.locality == nil ? "" : placemark.locality!
let subLocality = placemark.subLocality == nil ? "" : placemark.subLocality!
let thoroughfare = placemark.thoroughfare == nil ? "" : placemark.thoroughfare!
let subThoroughfare = placemark.subThoroughfare == nil ? "" : placemark.subThoroughfare!
let placeName = !thoroughfare.contains( subLocality ) ? subLocality : thoroughfare

//住所
let address = administrativeArea + locality + placeName + subThoroughfare

説明

プロパティ名 概要 説明
administrativeArea 都道府県 そのまま(nilにはならないはず)
subAdministrativeArea 町村の場合、localityに〜郡〜町/村と出力されるのでこちらは使用しません
locality 市区町村 そのまま(nilにはならないはず)
subLocality 丁番なしの地名 thoroughfareにsubLocalityが含まれない場合はsubLocality
thoroughfare 地名 上記以外はthoroughfare
subThoroughfare 番地 nilの場合は空白

実行結果

出力される住所は下記の画面の最終行に表示されています。

永田町2丁目 永田町 日比谷公園 奥多摩町
スクリーンショット 2019-11-26 23.49.06.png スクリーンショット 2019-11-26 23.58.09.png スクリーンショット 2019-11-26 23.53.09.png スクリーンショット 2019-11-26 23.51.56.png

実装

  1. 情報表示用のUILabelを追加
  2. 位置情報を利用許可状態を判定
  3. 位置情報の更新開始
  4. CLLocationデータを逆ジオコーディングして位置情報を取得
  5. 位置情報を住所に変換
  6. 位置情報が更新されるごとにUILabelに設定
import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {
    let locationManager = CLLocationManager()
    let geocoder = CLGeocoder()
    let text = [ "緯度", "経度", "国名", "郵便番号", "都道府県", "郡", "市区町村", "丁番なしの地名", "地名", "番地" ]
    var item: [ UILabel ] = []
    var location: [ UILabel ] = []
    var address: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //サイズ
        let width = self.view.frame.width / 2
        let height = self.view.frame.height / CGFloat( self.text.count + 2 )
        
        //ラベル
        for ( i, text ) in self.text.enumerated() {
            //項目
            self.item.append( UILabel() )
            self.item.last!.frame.size = CGSize( width: width, height: height )
            self.item.last!.frame.origin = CGPoint( x: 0, y: height * CGFloat( i + 1 ) )
            self.item.last!.textAlignment = .center
            self.item.last!.text = text
            self.view.addSubview( self.item.last! )
            
            //データ
            self.location.append( UILabel() )
            self.location.last!.frame.size = CGSize( width: width, height: height )
            self.location.last!.frame.origin = CGPoint( x: width, y: height * CGFloat( i + 1 ) )
            self.location.last!.textAlignment = .center
            self.view.addSubview( self.location.last! )
        }
        
        //住所
        self.address = UILabel()
        self.address.frame.size = CGSize( width: self.view.frame.width, height: height )
        self.address.frame.origin = CGPoint( x: 0, y: height * CGFloat( self.text.count + 1 ) )
        self.address.textAlignment = .center
        self.view.addSubview( self.address )
        
        //ロケーションマネージャ
        self.locationManager.requestWhenInUseAuthorization()
        let status = CLLocationManager.authorizationStatus()
        if status == .authorizedWhenInUse {
            self.locationManager.delegate = self
            self.locationManager.distanceFilter = 10
            self.locationManager.startUpdatingLocation()
        }
    }
    
    func locationManager( _ manager: CLLocationManager, didUpdateLocations locations: [ CLLocation ] ) {
        //表示更新
        if let location = locations.first {
            //緯度・経度
            self.location[0].text = location.coordinate.latitude.description
            self.location[1].text = location.coordinate.longitude.description
            
            //逆ジオコーディング
            self.geocoder.reverseGeocodeLocation( location, completionHandler: { ( placemarks, error ) in
                if let placemark = placemarks?.first {
                    //位置情報
                    self.location[2].text = placemark.country
                    self.location[3].text = placemark.postalCode
                    self.location[4].text = placemark.administrativeArea
                    self.location[5].text = placemark.subAdministrativeArea
                    self.location[6].text = placemark.locality
                    self.location[7].text = placemark.subLocality
                    self.location[8].text = placemark.thoroughfare
                    self.location[9].text = placemark.subThoroughfare
                    
                    //住所
                    let administrativeArea = placemark.administrativeArea == nil ? "" : placemark.administrativeArea!
                    let locality = placemark.locality == nil ? "" : placemark.locality!
                    let subLocality = placemark.subLocality == nil ? "" : placemark.subLocality!
                    let thoroughfare = placemark.thoroughfare == nil ? "" : placemark.thoroughfare!
                    let subThoroughfare = placemark.subThoroughfare == nil ? "" : placemark.subThoroughfare!
                    let placeName = !thoroughfare.contains( subLocality ) ? subLocality : thoroughfare
                    self.address.text = administrativeArea + locality + placeName + subThoroughfare
                }
            } )
        }
    }
}

Githubのソースコードはこちら

緯度・経度の確認方法について

住所から緯度・経度を確認するのに下記のサイトを使用しました。
いろいろな住所で変換結果が正しいことを確認するのに重宝しました。
https://www.geocoding.jp

このサイトで検索した緯度・経度を下記のように入力すると、その場所での位置情報を確認することができます。

//緯度・経度
let location = CLLocation( latitude: 35.675775, longitude: 139.743488 )
            
//逆ジオコーディング
self.geocoder.reverseGeocodeLocation( location, completionHandler: {
   //以下、略

参考

【CoreLocation】位置情報を取得する
[iOS] MapKitを使って”ジオコーディング・逆ジオコーディング”をやってみる

開発アプリ

この記事で紹介した位置情報の取得&住所変換処理を適用したアプリです。
Go Back Home - 自宅に帰るためのポータルアプリ

9
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?