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

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

Swiftでデータストアを位置情報検索する(半径検索)

f:id:mbaasdevrel:20180806093819p: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?

  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が呼び出されます。

@objc func handleTap(gestureReconizer: UILongPressGestureRecognizer) {
  let location = gestureReconizer.location(in: mapView)
  let coordinate = mapView.convert(location,toCoordinateFrom: mapView)

そしてこのデータを使って NCMBGeoPoint を作成します。

let geo = NCMBGeoPoint.init(latitude: coordinate.latitude, longitude: coordinate.longitude)

そして検索条件を作成します。今回はタップした場所から半径2キロとしています。

let query = NCMBQuery(className: "Station")
query?.whereKey("geo", nearGeoPoint: geo, withinKilometers: 2)

後は検索を実行して、返ってきた結果を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)
})

デモ

実際に動かしているところです。タップする度に、その近くにある山の手線の駅を表示します。

まとめ

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

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

中津川 篤司

中津川 篤司

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