CLLocationManager の使用方法は既に知っているので、デリゲートなどを使用して難しい方法で行うことができました。
しかし、現在の場所を一度だけ取得し、結果が得られるまでブロックする便利なメソッドが必要です。
CLLocationManager の使用方法は既に知っているので、デリゲートなどを使用して難しい方法で行うことができました。
しかし、現在の場所を一度だけ取得し、結果が得られるまでブロックする便利なメソッドが必要です。
私がやっていることは、コアの場所からの更新を管理するシングルトン クラスを実装することです。現在の場所にアクセスするには、CLLocation *myLocation = [[LocationManager sharedInstance] currentLocation];
次のようにします。メイン スレッドをブロックする場合は、次のようにします。
while ([[LocationManager sharedInstance] locationKnown] == NO){
//blocking here
//do stuff here, dont forget to have some kind of timeout to get out of this blocked //state
}
ただし、すでに指摘したように、メイン スレッドをブロックすることはおそらく良い考えではありませんが、何かを構築している場合、これは良い出発点になる可能性があります。また、私が作成したクラスは、場所の更新時にタイムスタンプをチェックし、古いものは無視して、コアの場所から古いデータを取得する問題を回避していることにも気付くでしょう。
これは私が書いたシングルトン クラスです。エッジの周りが少し粗いことに注意してください。
#import <CoreLocation/CoreLocation.h>
#import <Foundation/Foundation.h>
@interface LocationController : NSObject <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
CLLocation *currentLocation;
}
+ (LocationController *)sharedInstance;
-(void) start;
-(void) stop;
-(BOOL) locationKnown;
@property (nonatomic, retain) CLLocation *currentLocation;
@end
@implementation LocationController
@synthesize currentLocation;
static LocationController *sharedInstance;
+ (LocationController *)sharedInstance {
@synchronized(self) {
if (!sharedInstance)
sharedInstance=[[LocationController alloc] init];
}
return sharedInstance;
}
+(id)alloc {
@synchronized(self) {
NSAssert(sharedInstance == nil, @"Attempted to allocate a second instance of a singleton LocationController.");
sharedInstance = [super alloc];
}
return sharedInstance;
}
-(id) init {
if (self = [super init]) {
self.currentLocation = [[CLLocation alloc] init];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[self start];
}
return self;
}
-(void) start {
[locationManager startUpdatingLocation];
}
-(void) stop {
[locationManager stopUpdatingLocation];
}
-(BOOL) locationKnown {
if (round(currentLocation.speed) == -1) return NO; else return YES;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
//if the time interval returned from core location is more than two minutes we ignore it because it might be from an old session
if ( abs([newLocation.timestamp timeIntervalSinceDate: [NSDate date]]) < 120) {
self.currentLocation = newLocation;
}
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
UIAlertView *alert;
alert = [[UIAlertView alloc] initWithTitle:@"Error" message:[error description] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
-(void) dealloc {
[locationManager release];
[currentLocation release];
[super dealloc];
}
@end
そのような便利さはなく、自分で作成するべきではありません。「結果が出るまでブロックする」というのは、iPhoneのようなデバイスでは非常に悪いプログラミング手法です。場所の取得には数秒かかる場合があります。ユーザーをそのように待たせてはいけません。デリゲートはそうしないようにします。
自分でコーディングしない限り、"便利なメソッド" はありませんが、"便利な" ものにするために使用するカスタム コードにデリゲート メソッドを実装する必要があります。
デリゲート パターンが存在するのには理由があります。デリゲートは Objective-C の大部分であるため、慣れることをお勧めします。
ブラッド・スミスの回答に感謝します。実装してみると、彼が採用しているメソッドの 1 つが iOS6 で非推奨になっていることがわかりました。iOS5 と iOS6 の両方で動作するコードを作成するには、次を使用します。
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
if (abs([[locations lastObject] timeIntervalSinceDate:[NSDate date]]) < 120) {
[self setCurrentLocation:[locations lastObject]];
}
}
// Backward compatibility with iOS5.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSArray *locations = [NSArray arrayWithObjects:oldLocation, newLocation, nil];
[self locationManager:manager didUpdateLocations:locations];
}