Swift Playgroundsで学ぶiOSプログラミング

ユーザーがタップした地図の場所を突き止めるプログラミング

文●柴田文彦 編集●吉田ヒロ

2017年05月29日 17時00分

ジェスチャーを認識して位置を計算する

 以前にウェブキットといっしょにジェスチャー認識機能を使った際には、ユーザーが2本指で長押ししたという事実だけを使い、それが画面のどの位置だったかという情報は捨てていました。しかし、今回はその位置情報こそが重要です。そこで、設定したジェスチャーが認識されると自動的に呼び出されるメソッド(ここではhandlePress)の中で、その位置を割り出すことにします。これは、このメソッドにsenderとして渡されるジェスチャー認識オブジェクトのlocationメソッドで知ることができます。

 ただしこの位置は、ビュー、つまり画面上の座標です。そこに単にマークを付けるだけでなら、それでも構わないのですが、地図上の位置として利用するためには、それをマップキットの扱う地図上の座標に変換する必要があります。そのために使えるメソッドは、実はマップビュー自身が持っているconvertです。この変換の結果得られる座標をそのまま使って、地図上にアノテーションを追加することができます。

 以上説明したプログラムは、viewDidLoadとは別に、同じビューコントローラーの中に記述します。これについては、動かした結果とともに、やはり画面で確認してください。

ジェスチャーが認識されると呼び出されるhandlePressメソッドの中では、ジェスチャーのlocationメソッドでビュー上の座標を調べ、それをマップビューのconvertメソッドで地図上の座標に変換し、そこにアノテーションを設定しています

 このメソッドの先頭では、

if sender.state == .ended {
}

のようにして、ジェスチャー認識機能の状態を限定しています。これは、長押しの場合、そのジェスチャーの開始時点、途中、終了時など、何度もこのメソッドが呼び出されることになるため、ジェスチャーが終わった時にだけ反応するようにしたいからです。この結果、ユーザーが長押しした指を画面から離したときにアノテーションが追加されます。

コールアウトに緯度と経度を表示

 上で示したプログラムでは、アノテーションとして赤いピンを打つところまでのみで、ユーザーがピンに触れても、その位置に関する情報をコールアウトに表示するためのコードは含んでいません。そこで、とりあえずその位置の緯度と経度を表示してみることにしましょう。

 ビューの座標から地図の座標への変換はすでに済んでいるので、その座標から緯度と経度の情報を取り出すのは簡単です。変換後の座標を表す変数、pCoordのlatitudeとlongitudeのプロパティに、求める値が含まれています。ここではコールアウトに表示するタイトルとして「緯度, 経度」を設定し、サブタイトルには、緯度と経度をそれぞれ文字列に変換したものを「, 」で区切って設定しています。

 動作させた結果ととともにコードは画面で確認してください。

handlePressメソッドを拡張して、ユーザーが地図上を長押しした位置の座標を、緯度と経度の値としてコールアウトに表示するようにしました

住所を割り出してコールアウトに追加

 ここまでのプログラムで、ユーザーが画面にタッチした位置が単なるビューの座標ではなく、緯度と経度で表された地図上の座標として認識されていることが確認できました。しかし、緯度と経度の数字だけでは無味乾燥な感じが否めません。そこで緯度と経度の情報からその位置の住所を割り出して、アノテーションのコールアウトに表示してみることにします。

 地図上の座標から住所を割り出す処理は「逆ジオコーディング」と呼ばれています。つまり、住所から緯度と経度を割り出すのが「ジオコーディング」であり、その逆の処理ということです。この機能は、iOSではマップキットではなく、コアロケーション(Core Location)に含まれています。実際にはMapKitをインポートするだけでコアロケーションも利用可能となるので、別のフレームワークのインポートを追加する必要はありません。

 逆ジオコーディングの処理は比較的高度なもので、常に適切な住所が得られるとは限りません。また、インターネット上のサーバーにアクセスする必要もあり、それなりの時間がかかるだけでなく、どれくらいの時間がかかるかも事前にはわかりません。そのため、この機能を利用するには、処理が完了したら呼び出されるコンプリーション(完了)ハンドラーというものを用意する必要があります。

 このあたり、まだこの連載では扱っていない要素も多いので、簡単には説明しきれません。そこで今回は、必要なコードだけを示すことにします。

handlePressメソッドをさらに拡張して、ユーザーが長押しした位置の住所を逆ジオコーディング処理によって割り出し、コールアウトに表示するコードを追加しました

 ざっと読んでみていただければ、何をしているのかは理解できるはずです。住所情報が得られなかった場合には、「不明な住所」を表示するようにしています。実際に試した範囲では、これが表示されることはありませんでした。住所のないはずの海の中でも、日本近海では「日本」、太平洋の真ん中では「太平洋」などという「住所」が返ってくるからです。

 ピンチイン/アウトの操作で地図の縮尺を変えたり、ドラッグでスクロールさせたりして、いろいろな場所の住所を表示させてみてください。

地図上を長押ししてアノテーションを設定し、表示されたピンの頭にタッチすると、その位置の住居表示、緯度、経度を表示するコールアウトがポップアップします

次回の予定

 Swift Playgroundsのメジャーなアップデートによって利用可能になったマップキットは、さすがに見栄えのする、比較的派手な機能でした。それを、さっそく使ってみようということで、3回連続取り上げてきましたが、今回でマップキットの話はいったん締めくくることにします。このところiOSプログラミングの基本という路線からは少し外れていた感があります。その点を反省して、次回からは、地味ながら重要な機能のプログラミングに再び視点を戻すつもりです。

■今回作ったプログラム

Swift_40-1
Swift_40-1
Swift_40-3

mobileASCII.jp TOPページへ

mobile ASCII

Access Rankingアクセスランキング