iPhoneにはGPSセンサーが搭載されているが、GPS衛生からの電波だけでなくWi-Fiホットスポットや携帯の基地局から信号を使って位置特定の精度をあげているようだ。この部分についてはプログラムの実装上意識する必要はなく、単純にCoreLocationフレームワーク側でその時使える情報を元に位置特定をしてくれる。
CoreLocationフレームワークの追加
CoreLocation.frameworkをプロジェクトに追加しておく。
位置情報取得の流れ
位置情報の取得もUIAccelerometerによる加速度情報の取得のようにデリゲートを使った、Cocoaらしい実装方法になっている。
- CLLocationManagerのインスタンスを生成する
- 位置情報の取得を開始させる
- 位置情報が更新されると、デリゲート先として指定したオブジェクト上でメソッドが呼ばれる
startUpdatingLocationとstopUpdatingLocationメソッドで計測を開始/停止できる。なお、startUpdatingHeading/stopUpdatingHeadingメソッドを使うと方位情報の取得もできるようだが、残念ながら3GSが手元にないため実験できない。
位置情報が更新されると、locationManager:didUpdateToLocation:fromLocation:というメソッドが呼ばれる。引数には移動前と現在の地点の緯度と経度情報が入っているので、ここから現在の位置情報を取得することができる。
実際に実装してみると下記のような形になる。
LocationTracker.h
//
// LocationTracker.h
// gps_tracking
//
#import
#import
@interface LocationTracker : NSObject {
id _delegate;
CLLocationManager *locationManager;
BOOL isTracking;
float currentLatitude, currentLongitude;
}
@property (readonly) BOOL isTracking;
@property (readonly) float currentLatitude, currentLongitude;
- (id)initWithDelegate:(id)delegate;
- (void)startTracking;
- (void)stopTracking;
- (void)toggleTracking;
@end
LocationTracker.mm
//
// LocationTracker.mm
// gps_tracking
//
#import "LocationTracker.h"
@implementation LocationTracker
@synthesize isTracking, currentLatitude, currentLongitude;
- (id)initWithDelegate:(id)delegate{
if (self = [super init]){
_delegate = delegate;
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
isTracking = NO;
currentLatitude = 0.0f;
currentLongitude = 0.0f;
}
return self;
}
- (void)startTracking{
isTracking = YES;
[locationManager startUpdatingLocation];
}
- (void)stopTracking{
isTracking = NO;
[locationManager stopUpdatingLocation];
}
- (void)toggleTracking{
if (isTracking) {
[self stopTracking];
}else{
[self startTracking];
}
}
//位置情報が更新されたときに呼ばれるメソッドです
- (void)locationManager:(CLLocationManager*)manager
didUpdateToLocation:(CLLocation*)newLocation
fromLocation:(CLLocation*)oldLocation
{
CLLocationCoordinate2D coordinate = newLocation.coordinate;
currentLatitude = coordinate.latitude;
currentLongitude = coordinate.longitude;
//デリゲート先に情報が更新されたことを通知しておきます
[_delegate performSelector:@selector(locationUpdated:) withObject:self];
}
- (void)dealloc{
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
[locationManager release];
[super dealloc];
}
@end
コントローラ ヘッダファイル
//
// gps_trackingViewController.h
// gps_tracking
//
#import
#import "LocationTracker.h"
@interface gps_trackingViewController : UIViewController {
LocationTracker *tracker;
IBOutlet UILabel *currentLocationLabel;
}
- (IBAction)toggleTracking:(id)sender;
- (void)locationUpdated:(id)sender;
@end
コントローラ モジュールファイル(重要部分のみ)
- (IBAction)toggleTracking:(id)sender{
[tracker toggleTracking];
}
//LocationTracker側で位置情報が更新された時に呼ばれます
- (void)locationUpdated:(id)sender{
LocationTracker* _tracker = (LocationTracker*)sender;
[currentLocationLabel setText:[NSString stringWithFormat:@"%f, %f",
_tracker.currentLatitude, _tracker.currentLongitude]];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
tracker = [[LocationTracker alloc] initWithDelegate:self];
}
実際に上のコードを使って位置情報の取得を行おうとすると、確認ダイアログが表示される。
セキュリティの都合上、これを表示させないようにすることはプログラム側ではできないようだ。
OKを押すと計測が始まり、現在位置を取得することができた。なお、iPod touchでもWi-Fiの信号を元に位置特定ができるのだが、試しに実験してみたところアメリカのとある地点の位置情報が表示された(ここは日本)ので、どうやらあまり期待はできない模様。iPod touchでどうしても位置情報の取得が必要になる場合はPlace Engineのサービス開放に期待するしかなさそうだ。
参考資料: