什么';获取iPhone当前位置的最简单方法是什么?

什么';获取iPhone当前位置的最简单方法是什么?,iphone,core-location,Iphone,Core Location,我已经知道如何使用CLLocationManager,所以我可以用很难的方式完成它,有代表和所有这些 但是我希望有一个方便的方法,只获取当前位置,一次,并阻塞,直到得到结果。没有“方便方法”,除非您自己编写它们,但是您仍然需要在任何自定义代码中实现委托方法,以使事情“方便” 委托模式的存在是有原因的,由于委托是Objective-C的重要组成部分,我建议您熟悉它们。我要做的是实现一个singleton类来管理来自核心位置的更新。要访问我的当前位置,我执行CLLocation*myLocation

我已经知道如何使用CLLocationManager,所以我可以用很难的方式完成它,有代表和所有这些

但是我希望有一个方便的方法,只获取当前位置,一次,并阻塞,直到得到结果。

没有“方便方法”,除非您自己编写它们,但是您仍然需要在任何自定义代码中实现委托方法,以使事情“方便”


委托模式的存在是有原因的,由于委托是Objective-C的重要组成部分,我建议您熟悉它们。

我要做的是实现一个singleton类来管理来自核心位置的更新。要访问我的当前位置,我执行
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
#导入
#进口
@接口位置控制器:NSObject{
CLLocationManager*locationManager;
CLLocation*当前位置;
}
+(位置控制器*)共享状态;
-(无效)开始;
-(无效)停止;
-(BOOL)位置已知;
@属性(非原子,保留)CLLocation*currentLocation;
@结束
@实现位置控制器
@综合当前位置;
静态定位控制器*sharedInstance;
+(位置控制器*)共享状态{
@同步(自){
如果(!sharedInstance)
sharedInstance=[[LocationController alloc]init];
}
返回共享状态;
}
+(id)alloc{
@同步(自){
NSAssert(sharedInstance==nil,@“试图分配singleton LocationController的第二个实例”);
sharedInstance=[super alloc];
}
返回共享状态;
}
-(id)init{
if(self=[super init]){
self.currentLocation=[[CLLocation alloc]init];
locationManager=[[CLLocationManager alloc]init];
locationManager.delegate=self;
[自启动];
}
回归自我;
}
-(无效)开始{
[locationManager startUpdatingLocation];
}
-(无效)停止{
[locationManager停止更新位置];
}
-(BOOL)位置已知{
if(round(currentLocation.speed)=-1)返回否;否则返回是;
}
-(void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation{
//如果从核心位置返回的时间间隔超过两分钟,我们将忽略它,因为它可能来自旧会话
如果(abs([newLocation.timestamp-timeIntervalSinceDate:[NSDate-date]])<120{
self.currentLocation=新位置;
}
}
-(无效)locationManager:(CLLocationManager*)manager错误:(N错误*)错误{
UIAlertView*警报;
alert=[[UIAlertView alloc]initWithTitle:@“错误”消息:[错误描述]委托:nil CancelButtontile:@“确定”其他Buttontiles:nil];
[警报显示];
[警报发布];
}
-(无效)解除锁定{
[locationManager发布];
[当前位置释放];
[super dealoc];
}
@结束

没有这样的便利,你不应该创建自己的。在像iPhone这样的设备上,“阻塞直到得到结果”是极其糟糕的编程实践。检索位置可能需要几秒钟;你永远不应该让你的用户那样等待,代表们也要确保他们不会那样等待。

我很感激布拉德·史密斯的回答。在实现它时,我发现他使用的其中一种方法在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];
}
-(无效)位置管理器:(CLLocationManager*)管理器更新位置:(NSArray*)位置{
如果(abs([[locations lastObject]timeIntervalSinceDate:[NSDate date]])<120){
[self-setCurrentLocation:[locations lastObject]];
}
}
//与iOS5的向后兼容性。
-(void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation{
NSArray*locations=[NSArray arrayWithObjects:oldLocation,newLocation,nil];
[self locationManager:manager didUpdateLocations:locations];
}

我简化并组合了多个答案,其中位置只有在有效时才会更新

它也可以在OSX和iOS下工作

这假设用户突然需要当前位置的用例。在本例中,如果时间超过100毫秒,则视为错误。(假设GPS IC和| Wifi(苹果的Skyhook克隆)已经启动,并且已经有了很好的修复。)


你应该澄清这个问题:如果你知道如何使用CLLocationManager,那么实施这种“方便方法”有什么问题?我认为问题在于它不是那么容易。通常它首先返回一个旧的位置,然后是一个非常不准确的位置,然后是逐渐更好的位置,在什么时候你决定你拥有你想要的位置?这真的取决于你。线程,是的,当与完成时的回调相结合时。其中,回调被安排在原始运行循环上。这将为您提供一个与CLLocationManager的委托完全相同的接口。在终端用户应用程序中,“阻止直到完成”从来都不是一个好的设计。我不同意,“阻止直到完成”在各种应用程序中有许多合法的用途,并且不是“冻结UI直到完成”的同义词。试图使一切都异步只会导致奇怪的行为和错误的应用程序。谁会在乎UI显示/响应的速度有多快
#import "LocationManager.h"

// wait up to 100 ms
CLLocation *location = [LocationManager currentLocationByWaitingUpToMilliseconds:100];
if (!location) {
    NSLog(@"no location :(");
    return; 
}
// location is good, yay