ニフクラ mobile backend(mBaaS)お役立ちブログ

スマホアプリ開発にニフクラ mobile backend(mBaaS)。アプリ開発に役立つ情報をおとどけ!

Swiftでデータストアを位置情報検索する(2点間検索)

f:id:mbaasdevrel:20181006142604p:plain

mBaaSのデータストアでは位置情報を扱えます。位置情報なので、地図アプリや現実世界に合わせた情報を紹介するアプリなどに向いています。今回はデータストアを位置情報で検索して、返ってきた結果をMapKit上に表示します。

iOS SDKを導入する

イントロダクション (iOS) : クイックスタート | ニフクラ mobile backendを参考にiOS SDKを導入します。今回はCocoaPods版を導入しています。

MapKitを有効にする

XcodeのCapabilitiesタブでMapを有効にします。

info.plistを更新する

位置情報を扱うのでinfo.plistに項目を追加します。追加するのは以下の二つです。

  • Privacy - Location When In Use Usage Description
  • Privacy - Location Always and When In Use Usage Description

mBaaSを初期化する

アプリ起動時にNCMBを初期化します。今回はcocoapods-keysも使っています。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
  // Override point for customization after application launch.
  let keys = NcmbLocationKeys()
  NCMB.setApplicationKey(keys.applicationKey, clientKey: keys.clientKey)
  return true
}

Main.storyboardにMapViewなどを追加する

今回は以下のコンポーネントを追加しています。これらはViewController.swiftにアウトレットで接続しています。

  • MapView : MapView
  • Label : latitude
  • Label : longitude
  • Button : Start
  • Button : Stop

ViewControler.swiftにデリゲート追加

MapKitを扱うためのデリケートを追加します。

import MapKit

class ViewController: UIViewController, CLLocationManagerDelegate {
  @IBOutlet weak var mapView: MKMapView!
    @IBOutlet weak var latLabel: UILabel!
    @IBOutlet weak var lngLabel: UILabel!
  
  var locationManager : CLLocationManager?
  var locations: [CGPoint] = []

  func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .notDetermined:
            manager.requestWhenInUseAuthorization()
        case .restricted, .denied:
            break
        case .authorizedAlways, .authorizedWhenInUse:
            break
        }
    }

タップした場所の位置情報を取得

タップジェスチャーをトラッキングして、handleTapというメソッドを呼び出します。

override func viewDidLoad() {
  super.viewDidLoad()
  // Do any additional setup after loading the view, typically from a nib.
  // let gestureRecognizer = UITapGestureRecognizer(target: self, action:Selector("handleTap"))
  let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(gestureReconizer:)))
  gestureRecognizer.delegate = self as? UIGestureRecognizerDelegate
  mapView.addGestureRecognizer(gestureRecognizer)
}

こうするとタップ時にhandpleTapが呼び出されます。今回は2点使うので、位置情報を配列に入れておきます。

@objc func handleTap(gestureReconizer: UILongPressGestureRecognizer) {
  let location = gestureReconizer.location(in: mapView)
  self.locations.append(location)

そして、その配列の要素数に応じて処理分けします。要素が一つの場合は何もせず、二つの場合は検索を行います。3つの場合は検索結果と配列をクリアします。

switch self.locations.count {
case 2:
  self.searchStations()
case 3:
  self.mapView.removeAnnotations(self.mapView.annotations)
  self.locations.removeAll()
default:
  return;
}

検索を実行する

検索はsearchStationsというメソッドで行います。まず配列の中身を使って NCMBGeoPoint を作成します。

var geos: [NCMBGeoPoint] = []
for location in self.locations {
  let coordinate = mapView.convert(location,toCoordinateFrom: mapView)
  geos.append(NCMBGeoPoint.init(latitude: coordinate.latitude, longitude: coordinate.longitude))
}

そして検索条件を作成します。 withinGeoBoxFromSouthwest を使って、二点を指定します。

let query = NCMBQuery(className: "Station")
query?.whereKey("geo", withinGeoBoxFromSouthwest: geos[0], toNortheast: geos[1])

後は検索を実行して、返ってきた結果をMapKit上に表示します。

query?.findObjectsInBackground({(objects, err) in
  let stations = objects as! [NCMBObject]
  var annotations: [MKPointAnnotation] = []
  self.mapView.removeAnnotations(self.mapView.annotations)
  for station in stations {
    let geo = station.object(forKey: "geo") as! NCMBGeoPoint
    let location = CLLocation.init(latitude: geo.latitude, longitude: geo.longitude)
    let annotation = MKPointAnnotation()
    annotation.coordinate = location.coordinate
    annotations.append(annotation)
  }
  self.mapView.addAnnotations(annotations)
})

デモ

実際に動かしているところです。二つの場所をタップすると、その間にある山の手線の駅にマーカーを立てます。

f:id:mbaasdevrel:20181016191913g:plain

まとめ

mBaaSを使うことで、位置情報検索が簡単に実現できます。データに位置情報を紐付けて保存し、自分がいる場所の近くの情報だけを検索すると言ったことも簡単にできるでしょう。ぜひ皆さんのアプリで活用してください!

位置情報検索 (iOS) : 基本的な使い方 | ニフクラ mobile backend

中津川 篤司

中津川 篤司

NCMBエヴァンジェリスト。プログラマ、エンジニアとしていくつかの企業で働き、28歳のときに独立。 2004年、まだ情報が少なかったオープンソースソフトの技術ブログ「MOONGIFT」を開設し、毎日情報を発信している。2013年に法人化、ビジネスとエンジニアを結ぶDXエージェンシー「DevRel」活動をスタート。