読者です 読者をやめる 読者になる 読者になる

koogawa log

iOS、Android、foursquareに関する話題

【Tips】iOSで電子コンパスを使う(Swift編)

数年前に書いたこちらの記事が古くなってきたので、Swift として書き直しました。

blog.koogawa.com


f:id:koogawa:20160402095838p:plain

磁力センサーを利用し、iPhoneの向きを計測する方法を解説します。

「磁北」と「真北」について

単純に「北」と言っても、「磁北(じほく)」と「真北(しんぽく)」の二種類が存在します(2つの違いについては「真北とは? | 用語集とGISの使い方 | 株式会社パスコ」で丁寧に解説されています)。

ここでは磁北を取得する方法について解説します。

実行環境

実装方法

まずは「CoreLocation.framework」を追加します。

f:id:koogawa:20131122152458p:plain

次に Info.plist の NSLocationWhenInUseUsageDescription位置情報を使用する目的 を記載します。この内容はユーザに位置情報の使用を許可する際に表示されます。

f:id:koogawa:20160326145627p:plain

CoreLocation をインポートしましょう。

import CoreLocation

CLLocationManagerDelegate プロトコルを宣言します。

class ViewController: UIViewController, CLLocationManagerDelegate {

ユーザが位置情報の使用を許可しているか確認します。許可状況は didChangeAuthorizationStatus デリゲートで確認できます。初回は NotDetermined ステータスが返るので、requestWhenInUseAuthorization() メソッドでユーザに許可を求めます。

func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    switch status {
    case .NotDetermined:
        locationManager.requestWhenInUseAuthorization()
    case .Restricted, .Denied:
        break
    case .Authorized, .AuthorizedWhenInUse:
        break
    }
}

これで準備が整いました。さっそく、ヘディングイベントの取得を開始してみましょう。

if CLLocationManager.locationServicesEnabled() {
    locationManager = CLLocationManager()
    locationManager.delegate = self
    
    // 何度動いたら更新するか(デフォルトは1度)
    locationManager.headingFilter = kCLHeadingFilterNone
    
    // デバイスのどの向きを北とするか(デフォルトは画面上部)
    locationManager.headingOrientation = .Portrait

    locationManager.startUpdatingHeading()
}

この状態でiPhoneの向きが変わると、次のメソッドが呼ばれます。

func locationManager(manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
    self.textField.text = "".stringByAppendingFormat("%.2f", newHeading.magneticHeading)
}

magneticHeading には 0.0 から 359.9 の値が入ります。北の方向がちょうど 0.0 になり、それから東、南、西の順に値が増えていき、北に戻ると再び 0.0 に戻ります。

方角
0.0
90.0
180.0
西 270.0

ヘディングイベントの取得を停止するには次のメソッドを実行します。

if CLLocationManager.locationServicesEnabled() {
    locationManager.stopUpdatingHeading()
}

イベントの取得が不要になったら、忘れずに停止しておきましょう。

サンプルコード

注意点

応用できそうなアプリ

参考リンク