連載
» 2011年04月04日 00時00分 公開

iOSでジオ(GEO)プログミラング入門(1):iPhoneアプリで位置情報と地図を使うための基礎知識 (2/3)

[郷田まり子,株式会社鳥人間]

CoreLocationで現在地の緯度経度を取得するには

 では、CoreLocationフレームワークを利用して、現在地の緯度・経度を取得してみましょう。

 メインの画面を扱う「GeoPhotoViewController」クラスを編集します。

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

@interface GeoPhotoViewController : UIViewController <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
}

@property (nonatomic, retain) CLLocationManager *locationManager;

@end
GeoPhotoViewController.h
#import "GeoPhotoViewController.h"
 
@implementation GeoPhotoViewController
@synthesize locationManager;
 
- (void)viewDidLoad {
    [super viewDidLoad];
    locationManager = [[CLLocationManager alloc] init];
 
    // 位置情報サービスが利用できるかどうかをチェック
    if ([CLLocationManager locationServicesEnabled]) {
        locationManager.delegate = self; // ……【1】
        // 測位開始
        [locationManager startUpdatingLocation];
    } else {
        NSLog(@"Location services not available.");
    }
}
 
// 位置情報更新時
- (void)locationManager:(CLLocationManager *)manager 
didUpdateToLocation:(CLLocation *)newLocation 
fromLocation:(CLLocation *)oldLocation {
 
    //緯度・経度を出力
    NSLog(@"didUpdateToLocation latitude=%f, longitude=%f",
        [newLocation coordinate].latitude,
        [newLocation coordinate].longitude);
}
 
// 測位失敗時や、5位置情報の利用をユーザーが「不許可」とした場合などに呼ばれる
- (void)locationManager:(CLLocationManager *)manager 
didFailWithError:(NSError *)error{
    NSLog(@"didFailWithError");
}
 
- (void)dealloc {
    [locationManager release];
    [super dealloc];
}
@end
GeoPhotoViewController.m

 「CLLocationManager」は、測位電子コンパス地磁気センサ)を取り扱うクラスです。

 【1】の部分に注目してください。生成したCLLocationManagerインスタンスのデリゲートとして、このGeoPhotoViewControllerインスタンス自身(「 = self」)をセットしています。

 CLLocationManagerは、「位置の更新」「測位のエラー」などのイベントが起こると、そのイベントの処理をデリゲートに委譲します。デリゲート側は、「CLLocationManagerDelegateプロトコルに定義されたメソッド実装し、それらのイベントをハンドリングする必要があります。「didUpdateToLocation」「didFailWithError」メソッドが、それに当たります。

 これを動かしてみると、現在地の緯度経度がコンソールに出力されます。

didUpdateToLocation latitude=35.699220, longitude=139.745229
コンソール出力の例

位置情報取得機能は電気の消費が激しい!

 位置情報アプリの開発には欠かせない測位機能ですが、1つ欠点があります。測位機能を使っていると、バッテリの消費が多くなってしまうのです。使っていると、すぐにバッテリがなくなってしまうようなアプリは嫌われてしまいますよね。

 先ほどのコードを少し改造して、アプリケーションがスリープしたときに測位機能をオフにし、復帰した際にオンにするようにします。

 アプリケーション全体の動きを取り扱うのが、「UIKit」フレームワークの「UIApplication」クラスです。アプリケーションのスリープや復帰も、この「UIApplication」のイベントとして扱われます。

 今回の例では、プロジェクト作成時に自動生成された「GeoPhotoAppDelegate」クラスが、「UIApplication」のデリゲートとして機能します。アプリケーションがアクティブになると、「applicationDidBecomeActive」メソッドが、非アクティブになると「applicationWillResignActive」メソッドが呼ばれるので、この2つのイベントハンドラに測位機能のオン/オフを書き加えます。

 まず、「GeoPhotoViewController」に、「onResume」「onPause」の2つのメソッドを新たに追加し、それぞれ、測位機能をオン/オフにする処理を書きます。

-(void) onResume;
-(void) onPause;
GeoPhotoViewController.h
-(void) onResume {
    if (nil == locationManager && [CLLocationManager locationServicesEnabled])
        [locationManager startUpdatingLocation]; //測位再開
}
 
-(void) onPause {
    if (nil == locationManager && [CLLocationManager locationServicesEnabled])
        [locationManager stopUpdatingLocation]; //測位停止
}
GeoPhotoViewController.m

 GeoPhotoAppDelegateクラスのapplicationDidBecomeActiveメソッドとapplicationWillResignActiveメソッドから、これをコールします。

- (void)applicationWillResignActive:(UIApplication *)application {
    NSLog(@"applicationWillResignActive");
    [viewController onPause];
}
 
- (void)applicationDidBecomeActive:(UIApplication *)application {
    NSLog(@"applicationDidBecomeActive");
    [viewController onResume];
}
GeoPhotoAppDelegate.m

 これで、アプリを使っているときだけ測位を行う「省エネ」なアプリになりました。

 スリープやレジュームで切り替えるというのは、バッテリ節約のためのアイデアのほんの一例です。例えば、位置情報を使った検索や投稿を行うアプリなら、検索する直前だけ位置を取得するなど、「本当に必要なとき」だけ測位するように心掛けましょう。

MapKitで地図を追加するには

 さて、次は地図です。GeoPhotoViewControllerクラスのプロパティとして、「MKMapView」クラスを追加します。

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

@interface GeoPhotoViewController : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate> {
IBOutlet MKMapView *mapView;
CLLocationManager *locationManager;
}

@property (nonatomic, retain) CLLocationManager *locationManager;
@property (nonatomic, retain) IBOutlet MKMapView *mapView;

……【略】……
GeoPhotoViewController.h(太字部分を追加)

 「GeoPhotoViewController.xib」をInterface Builderで開いて、アウトレットを接続します。もちろん、Interface Builderを使わずにコードだけでUIを作っても構いません。

 ライブラリから「MapView」を選んでViewに配置します。

 [File's Owner]の「mapView」と接続します。

 現在地が更新されたときに呼ばれる「didUpdateToLocation」メソッドを編集します。現在地に合わせてセンタリングし、地図のパン(表示範囲の変更)とズーム(縮尺の変更)を行います。

- (void)locationManager:(CLLocationManager *)manager 
didUpdateToLocation:(CLLocation *)newLocation 
fromLocation:(CLLocation *)oldLocation {
    NSLog(@"didUpdateToLocation latitude=%f, longitude=%f",
    [newLocation coordinate].latitude,
    [newLocation coordinate].longitude);
    MKCoordinateRegion region = MKCoordinateRegionMake([newLocation coordinate], MKCoordinateSpanMake(1.75, 1.75));
    [mapView setCenterCoordinate:[newLocation coordinate]];
    [mapView setRegion:region];
}

 地図のパンを行うには「MKMapView#setCenterCoordinate」メソッドを使います。

 範囲を決めて表示するときは「MKMapView#setRegion」メソッドです。このとき渡すのは 「MKCoordinateRegion」構造体です。中央の緯度経度(CLLocationCoordinate)と、表示する緯度・経度の幅(MKCoordinateSpan)の情報を持ちます。

 次ページでは、アノテーションを追加する方法と、デフォルトの赤いピンをカスタマイズする方法をコードを交えて解説します。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。