では、CoreLocationフレームワークを利用して、現在地の緯度・経度を取得してみましょう。
メインの画面を扱う「GeoPhotoViewController」クラスを編集します。
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@interface GeoPhotoViewController : UIViewController <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
}
@property (nonatomic, retain) CLLocationManager *locationManager;
@end
#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
「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;
-(void) onResume {
if (nil == locationManager && [CLLocationManager locationServicesEnabled])
[locationManager startUpdatingLocation]; //測位再開
}
-(void) onPause {
if (nil == locationManager && [CLLocationManager locationServicesEnabled])
[locationManager stopUpdatingLocation]; //測位停止
}
GeoPhotoAppDelegateクラスのapplicationDidBecomeActiveメソッドとapplicationWillResignActiveメソッドから、これをコールします。
- (void)applicationWillResignActive:(UIApplication *)application {
NSLog(@"applicationWillResignActive");
[viewController onPause];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSLog(@"applicationDidBecomeActive");
[viewController onResume];
}
これで、アプリを使っているときだけ測位を行う「省エネ」なアプリになりました。
スリープやレジュームで切り替えるというのは、バッテリ節約のためのアイデアのほんの一例です。例えば、位置情報を使った検索や投稿を行うアプリなら、検索する直前だけ位置を取得するなど、「本当に必要なとき」だけ測位するように心掛けましょう。
さて、次は地図です。GeoPhotoViewControllerクラスのプロパティとして、「MKMapView」クラスを追加します。
「GeoPhotoViewController.xib」をInterface Builderで開いて、アウトレットを接続します。もちろん、Interface Builderを使わずにコードだけでUIを作っても構いません。
ライブラリから「MapView」を選んでViewに配置します。
[File's Owner]の「mapView」と接続します。
現在地が更新されたときに呼ばれる「didUpdateToLocation」メソッドを編集します。現在地に合わせてセンタリングし、地図のパン(表示範囲の変更)とズーム(縮尺の変更)を行います。
地図のパンを行うには「MKMapView#setCenterCoordinate」メソッドを使います。
範囲を決めて表示するときは「MKMapView#setRegion」メソッドです。このとき渡すのは 「MKCoordinateRegion」構造体です。中央の緯度経度(CLLocationCoordinate)と、表示する緯度・経度の幅(MKCoordinateSpan)の情報を持ちます。
次ページでは、アノテーションを追加する方法と、デフォルトの赤いピンをカスタマイズする方法をコードを交えて解説します。
Copyright © ITmedia, Inc. All Rights Reserved.