mBaaSのデータストアでは位置情報を扱えます。位置情報なので、地図アプリや現実世界に合わせた情報を紹介するアプリなどに向いています。今回はデータストアを位置情報で検索して、返ってきた結果をMapKit上に表示します。
- iOS SDKを導入する
- MapKitを有効にする
- info.plistを更新する
- mBaaSを初期化する
- Main.storyboardにMapViewなどを追加する
- ViewControler.swiftにデリゲート追加
- タップした場所の位置情報を取得
- 検索を実行する
- デモ
- まとめ
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) })
デモ
実際に動かしているところです。二つの場所をタップすると、その間にある山の手線の駅にマーカーを立てます。
まとめ
mBaaSを使うことで、位置情報検索が簡単に実現できます。データに位置情報を紐付けて保存し、自分がいる場所の近くの情報だけを検索すると言ったことも簡単にできるでしょう。ぜひ皆さんのアプリで活用してください!