TL;DR
iOS標準Mapkitには、実は、自然言語(例:コンビニ 新宿)でプレイス検索ができるMKLocalSearchが存在します!
Google Places APIほどの精度はありませんが、クレカ登録などの面倒な手続きを踏まずに利用できる便利なAPIです。
その実装方法を紹介します。Swift 4.2です。
更新
- 2019/02/14 コードの整理とSwift 4.2対応
準備
まずMKPlacemarkを拡張します。
MKPlacemarkは、都道府県、市区町村、番地などのプロパティを持っていますが、
「東京都渋谷区千駄ヶ谷1-2-3」のような出力をするには、これらひとつひとつ連結しなくてはなりません。
そこでaddressというComputed Propertyを持たせます。
import MapKit
extension MKPlacemark {
var address: String {
let components = [self.administrativeArea, self.locality, self.thoroughfare, self.subThoroughfare]
return components.compactMap { $0 }.joined(separator: "")
}
}
英語の場合は、↓の表記ですね。
return components.reversed().compactMap{ $0 }.joined(separator: ",")
検索メソッド
ここで用意した引数は2つです。
queryには自然言語(例:コンビニ 新宿)を渡し、regionにはMKCoordinateRegionを渡すとヒントとして利用され、検索精度の向上が見込めます(任意)。
struct Map {
enum Result<T> {
case success(T)
case failure(Error)
}
static func search(query: String, region: MKCoordinateRegion? = nil, completionHandler: @escaping (Result<[MKMapItem]>) -> Void) {
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = query
if let region = region {
request.region = region
}
MKLocalSearch(request: request).start { (response, error) in
if let error = error {
completionHandler(.failure(error))
return
}
completionHandler(.success(response?.mapItems ?? []))
}
}
}
基準となるRegionを渡し、検索実行!
検索には、座標と検索範囲のregionを設定します。
let coordinate = CLLocationCoordinate2DMake(35.6598051, 139.7036661) // 渋谷ヒカリエ
let region = MKCoordinateRegion(center: coordinate, latitudinalMeters: 1000.0, longitudinalMeters: 1000.0) // 1km * 1km
Map.search(query: "コンビニ", region: region) { (result) in
switch result {
case .success(let mapItems):
for map in mapItems {
print("name: \(map.name ?? "no name")")
print("coordinate: \(map.placemark.coordinate.latitude) \(map.placemark.coordinate.latitude)")
print("address \(map.placemark.address)")
}
case .failure(let error):
print("error \(error.localizedDescription)")
}
}
結果
[MKMapItem]
が検索結果として返ってきます
#map name: ローソン渋谷三丁目店
#map coordinate: 35.6560398 35.6560398
#map address 東京都渋谷区渋谷3丁目28番8号
#map name: ファミリーマート麹町二丁目店
#map coordinate: 35.6834507 35.6834507
#map address 東京都千代田区麹町2丁目5番4号
#map name: ナチュラルローソン&フードクルック 神宮外苑西店
#map coordinate: 35.671825 35.671825
#map address 東京都渋谷区神宮前3丁目35番8号
あとは、Mapにannotationを立てるなり、Cellに表示するなりしてください!