今回はCLLocationManagerを使った位置情報取得の説明です。iOS 6対応です。

サンプル: https://github.com/stack3/CLLocationManagerSamples

サンプルを起動して、Get Locationを選択すると以下の画面が表示されます。

01

Startボタンを押すと一度目は以下の様なAlertが表示され、このアプリで位置情報取得を許可して良いかユーザーに確認します。

02

※ シミュレータでは言語設定が日本語でも英語で表示されるかもしれません

ここで許可するを押すと、位置情報取得が開始され、latitude、longitudeに値が入るはずです。許可しないを押すと、このアプリでは位置情報取得ができなくなります。この場合、iOSの設定を開き、プライバシー > 位置情報から再度設定出来ます。

03-1

Startを押し位置情報が許可されれば、位置情報の取得が始まり、latitude、longitudeが更新され続けます。この時、右上に位置情報取得アイコンが表示されます。

04-1

Stopを押すと位置情報の取得が停止します。

CLLocationManagerクラス

位置情報の取得はCLLocationManagerクラスを使います。CoreLocation.frameworkをプロジェクトに追加することで使えるようになります。

06

今回使うCLLocationManagerのメソッドは以下のとおり。

startUpdatingLocation 位置情報取得を開始
stopUpdatingLocation 位置情報取得を停止

startUpdatingLocationを呼ぶとstopUpdatingLocationが呼ばれるまで、現在の位置情報を取得し続け、新しい位置情報が得られるごとに、CLCoreLocationManagerDelegate#locationManager:didUpdateLocations:が呼ばれます。stopUpdatingLocationを呼ぶと位置情報の取得を停止し、delegateメソッドも呼ばれなくなります。

位置情報取得はバッテリ消費が上がるので、位置情報取得が必要なくなったらstopUpdatingLocationで停止すべきでしょう。

CLLocationクラス

位置情報を示すクラスです。主に使うのは以下のプロパティです。

coordinate.latitude 緯度
coordinate.longitude 経度
timestamp 位置情報取得日時

STGetLocationViewControllerクラス

この画面用のViewControllerです。

STGetLocationViewController.hで、CoreLocation.hをimportし、CLLocationManagerDelegateを実装できるようにします。

#import <CoreLocation/CoreLocation.h>

@interface STGetLocationViewController : UIViewController<CLLocationManagerDelegate>

@end

メンバ変数は以下のとおり。それぞれxib上のSubviewとひもづけられています。

@implementation STGetLocationViewController {
    // 緯度(latitude)表示用のTextField
    IBOutlet __weak UITextField *_latitudeField;
    // 経度(longitude)表示用のTextField
    IBOutlet __weak UITextField *_longitudeField;
    // 位置情報取得開始ボタン
    IBOutlet __weak UIButton *_startButton;
    // 位置情報取得終了ボタン
    IBOutlet __weak UIButton *_stopButton;
    // CLLocationManager
    __strong CLLocationManager *_locationManager;
}

viewDidLoadで、CLLocationManagerを生成して、_locationManagerへ代入。あとはstartButtonとstopButtonが押された時のイベントメソッドを設定。

- (void)viewDidLoad
{
    [super viewDidLoad];

    _locationManager = [[CLLocationManager alloc] init];
    _locationManager.delegate = self;
    
    [_startButton setTitleColor:[UIColor grayColor] forState:UIControlStateDisabled];
    [_startButton addTarget:self action:@selector(didTapStartButton) forControlEvents:UIControlEventTouchUpInside];
    
    [_stopButton setTitleColor:[UIColor grayColor] forState:UIControlStateDisabled];
    [_stopButton addTarget:self action:@selector(didTapStopButton) forControlEvents:UIControlEventTouchUpInside];
}

viewDidLoadでは_locationManagerを解放するようにしておきます。viewが非表示の時は位置情報取得する必要がないので。

- (void)viewDidUnload
{
    [super viewDidUnload];
    
    _locationManager.delegate = nil;
    _locationManager = nil;
}

startButtonが押された時は、CLLocationManager#startUpdatingLocationで位置情報取得を開始します。

- (void)didTapStartButton
{
    [_locationManager startUpdatingLocation];
    // startButtonを使用不可にする
    _startButton.enabled = NO;
    // stopButtonを使用可にする
    _stopButton.enabled = YES;
    NSLog(@"start updating location. timestamp:%@", [[NSDate date] description]);
}

アプリをインストールして最初にstartUpdatingLocationを呼んだ時に、以下の位置情報取得許可のAlertが表示されます。

02

stopButtonが押された時は、CLLocationManager#stopUpdatingLocationで位置情報取得を停止します。

- (void)didTapStopButton
{
    [_locationManager stopUpdatingLocation];
    // startButtonを使用可にする
    _startButton.enabled = YES;
    // stopButtonを使用不可にする
    _stopButton.enabled = NO;
}

位置情報が取得される度に呼ばれるdeleteメソッドで、取得した位置情報を表示します。

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    // もっとも最近の位置情報を得る
    CLLocation *recentLocation = locations.lastObject;
    _latitudeField.text = [NSString stringWithFormat:@"%f", recentLocation.coordinate.latitude];
    _longitudeField.text = [NSString stringWithFormat:@"%f", recentLocation.coordinate.longitude];
    NSLog(@"location:%f %f timestamp:%@", recentLocation.coordinate.latitude, recentLocation.coordinate.longitude, recentLocation.timestamp.description);
}

locationsの一番最後の要素が最新の現在位置情報(CLLocation)になるので、locations.lastObjectで取得しています。

※ ちなみにこのdelegateメソッドは、iOS 6から有効になりました。以前は、locationManager:didUpdateToLocation:fromLocation:というメソッドでしたdeprecatedになりました。

位置情報取得に失敗した時に呼ばれるdelegateで、latitudeFieldとlongitudeFieldの表示を—とします。

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    _latitudeField.text = @"---";
    _longitudeField.text = @"---";
}

このメソッドは、GPS取得できない屋内にいたり、位置情報取得許可のAlertでDon’t Allow(許可しない)を選択された状態で、startUpdatingLocationを呼んだ時などに呼ばれるようになります。

その2へ続く