Help us understand the problem. What is going on with this article?

Swiftで位置検索ができるMapアプリの開発

何をやるのか?

今回はSwiftでの簡易的なMapアプリの開発を説明していく。
geocoderを用いた、緯度・経度の情報指定により検索ワードからその位置を割り出していく。

前提

xcodeのstoryboardにてMapKit、textfieldがすでに設置済みとして、プログラミングにおけるロジックにのみ焦点を当てて解説していく。

TextFieldの入力時の完了通知を受け取る

import UIKit
import MapKit

class ViewController: UIViewController , UITextFieldDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        inputText.delegate = self
    }

まずtextField のdelegate機能を使うために、ViewControllerに対してUITextFieldDelegateを宣言します。
そしてinputText.delegate = self を追記することで、初期画面表示前にTextField のdelegate通知先を設定します。
上記のdelegate通知先設定のコードを追記したviewDidLoad()メソッドは、初めて画面が表示される時に実行されるメソッドであるため、このメソッド内に追記します。

文字入力後の処理

@IBOutlet weak var inputText: UITextField!
<!-- storybordからのGUI操作で宣言TextField検索窓を宣言(表してしている -->
@IBOutlet weak var Map: MKMapView!
<!-- storybordからのGUI操作で宣言MapKit地図を宣言(表してしている -->

func textFieldShouldReturn(_ textField: UITextField) -> Bool {

  //キーボードを閉じる。resignFirstResponderはdelegateメソッド
  textField.resignFirstResponder()

  //入力された文字を取り出す
   if let searchKey = textField.text {

     //入力された文字をデバッグエリアの表示
     print(searchKey)
   }
  //デフォルト動作を行うのでtureを返す。返り値型をBoolにしているため、この記述がないとエラーになる。
   return true
}

ここまでで検索窓から入力された値を取ってくる作業で終了です。

 キーワードから緯度経度を検索する

print(searchKey)

//CLGeocoderインスタンスを取得
let geocoder = CLGeocoder()

//入力された文字から位置情報を取得
geocoder.geocodeAddressString(searchKey, completionHandler: { (placemarks, error) in

 //位置情報が存在する場合(定数geocoderに値が入ってる場合)はunwrapPlacemarksに取り出す。
if let unwrapPlacemark = placemarks {

  //1件目の情報を取り出す
 if let firstPlacemark = unwrapPlacemarks.first {

   //位置情報を取り出す
   if let location = firstPlacemark.location {

     //位置情報から緯度経度をtargetCoordinateに取り出す
      let targetCoordinate = location.coordinate
      //緯度経度をデバッグエリアに表示
      print(targetCoordinate)
   }
  }
}
})
}
 return true
}
}

まず最初にCLGeocoderインスタンスを生成します。
CLGeocoderクラスを使うと、緯度経度から住所を検索することができます。また、住所から緯度経度を検索することだできます。


//CLGeocoderインスタンスを取得
let geocoder = CLGeocoder(

住所などの文字列から位置情報を取得するまでのメソッドです。
これは「クロージャ]という機能を使っています。クロージャとはここでは詳しく説明しませんが、関数とよく似た機能だと思ってください。
位置情報はクロージャ内に結果が通知され、位置情報が検索できたタイミングで{}内が実行されます。

geocoder.geocodeAddressString(searchKey, completionHandler: { (placemarks, error) in
}

通知された位置情報「placemarks」は現在の状態ではnillを含んでいる可能性がある、オプショナル型です。
そのためここからオプショナルバインディングを用いてアンラップすると同時に、情報を精査しという作業を繰り返します。
最終的にはtargetCoordinateにその地名の緯度経度の情報を格納します。

if let unwrapPlacemark = placemarks {

  //1件目の情報を取り出す
 if let firstPlacemark = unwrapPlacemarks.first {

   //位置情報を取り出す
   if let location = firstPlacemark.location {

     //位置情報から緯度経度をtargetCoordinateに取り出す
      let targetCoordinate = location.coordinate
      //緯度経度をデバッグエリアに表示
      print(targetCoordinate)

マップ上にピンを置く

//MKPointAnnotationインスタンスを取得し、ピンを生成
 let pin = MKPointAnnotation()

//ピンの置く場所に緯度経度を設定
 pin.coordinate = targetCoordinate

//ピンのタイトルを設定
 pin.title = searchKey

//ピンを地図に置く
 self.Map.addAnnotation(pin)

//検索地点の緯度経度を中心に半径500mの範囲を表示                            
 self.Map.region = MKCoordinateRegion(center: targetCoordinate, latitudinalMeters: 500.0, longitudinalMeters: 500.0)

上記の通り、ピンの生成 → ピンに緯度経度を設定・タイトルを設定 → ピンを地図におく → 地図を拡大 という流れで検索地点を表示します。

最後にコード全体

import UIKit
import MapKit

class ViewController: UIViewController , UITextFieldDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        inputText.delegate = self
    }


    @IBOutlet weak var inputText: UITextField!
    @IBOutlet weak var Map: MKMapView!

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()

        if let searchKey = textField.text {

        print(searchKey)

        let geocoder = CLGeocoder()

            geocoder.geocodeAddressString(searchKey, completionHandler: { (placemarks, error) in

                if let unwrapPlacemarks = placemarks {
                    if let firstPlacemark = unwrapPlacemarks.first {
                        if let location = firstPlacemark.location {
                            let targetCoordinate = location.coordinate
                            print(targetCoordinate)

                            let pin = MKPointAnnotation()

                            pin.coordinate = targetCoordinate
                            pin.title = searchKey
                            self.Map.addAnnotation(pin)

                            self.Map.region = MKCoordinateRegion(center: targetCoordinate, latitudinalMeters: 500.0, longitudinalMeters: 500.0)
                        }
                    }
                }
            })
    }
    return true
}


}

Howasuto
iOSエンジニア
tresInnovation
当社は新しいアイディアから社会的意義のある新たな価値を創造し、社会に大きな変化をもたらす組織、社会の幅広い変革に貢献できるような会社を創る事をモットーにしております。VR事業、HR事業、EC事業、クリエイティブ事業、広告事業と多岐に渡る事業内容で世の中にワクワクを創造している会社です!
https://tresinnovation.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away