I already know how to use the CLLocationManager, so I could do it the hard way, with delegates and all that.
我已经知道如何使用CLLocationManager,所以我可以用委托和所有的方法来做。
But I'd like to have a convenience method that just gets the current location, once, and blocks until it gets the result.
但是我希望有一个方便的方法,它只获取当前位置一次,然后阻塞,直到得到结果。
5 个解决方案
#1
45
What I do is implement a singleton class to manage updates from core location. To access my current location, I do a CLLocation *myLocation = [[LocationManager sharedInstance] currentLocation];
If you wanted to block the main thread you could do something like this:
我所做的是实现一个单例类来管理来自核心位置的更新。为了访问当前位置,我执行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
}
However, as it has been already pointed out, blocking the main thread is probably not a good idea, but this can be a good jumping off point as you are building something. You will also notice that the class I wrote checks the timestamp on location updates and ignores any that are old, to prevent the problem of getting stale data from core location.
然而,正如前面已经指出的,阻塞主线程可能不是一个好主意,但是当您正在构建某些东西时,这可能是一个很好的起点。您还将注意到,我编写的类检查位置更新的时间戳,并忽略任何旧的,以防止从核心位置获取过时的数据。
This is the singleton class I wrote. Please note that it is a little rough around the edges:
这是我编写的单例类。请注意边缘有点粗糙:
#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
#2
7
There is no such convenience and you shouldn't create your own. "Blocks until it gets the result" is extremely bad programming practice on a device like the iPhone. It can take seconds to retrieve a location; you should never make your users wait like that, and delegates ensure they don't.
没有这种方便,你不应该创建自己的。在iPhone这样的设备上,“阻塞直到得到结果”是极其糟糕的编程实践。检索位置可能需要几秒钟;你不应该让你的用户那样等待,委托确保他们不会。
#3
4
There are no "convenience methods" unless you code them yourself, but you'd still need to implement the delegate methods in whatever custom code you use to make things "convenient."
没有“方便方法”,除非您自己编写它们,但是您仍然需要在您使用的任何自定义代码中实现委托方法,以使事情“方便”。
The delegate pattern is there for a reason, and as delegates are a big part of Objective-C, I recommend you get comfortable with them.
委托模式的存在是有原因的,由于委托是Objective-C的重要组成部分,我建议您熟悉它们。
#4
0
I appreciated the answer by Brad Smith. Implementing it I discovered that one of the methods he employs is deprecated as of iOS6. To write code that will work with both iOS5 and iOS6, use the following:
我很欣赏布拉德·史密斯的回答。实现它时,我发现他使用的方法之一是不赞成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];
}
#5
0
I simplified and combined multiple answers to where the location is only updated if it's valid.
我简化并组合了多个答案,只有在位置有效时才更新。
It also works under OSX as well as iOS.
它也适用于OSX和iOS。
This assumes the use-case where the current location is suddenly desired by the user. If it takes more than 100 ms in this example, it's considered an error. (Assumes the GPS IC &| Wifi (Apple's Skyhook clone) is already fired up and has a good fix already.)
这假设用户突然需要当前位置的用例。如果在本例中需要超过100ms,则视为错误。(假设GPS IC和| Wifi(苹果的Skyhook克隆产品)已经启动,并且已经得到了很好的修复。)
#import "LocationManager.h"
// wait up to 100 ms
CLLocation *location = [LocationManager currentLocationByWaitingUpToMilliseconds:100];
if (!location) {
NSLog(@"no location :(");
return;
}
// location is good, yay
https://gist.github.com/6972228
https://gist.github.com/6972228
#1
45
What I do is implement a singleton class to manage updates from core location. To access my current location, I do a CLLocation *myLocation = [[LocationManager sharedInstance] currentLocation];
If you wanted to block the main thread you could do something like this:
我所做的是实现一个单例类来管理来自核心位置的更新。为了访问当前位置,我执行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
}
However, as it has been already pointed out, blocking the main thread is probably not a good idea, but this can be a good jumping off point as you are building something. You will also notice that the class I wrote checks the timestamp on location updates and ignores any that are old, to prevent the problem of getting stale data from core location.
然而,正如前面已经指出的,阻塞主线程可能不是一个好主意,但是当您正在构建某些东西时,这可能是一个很好的起点。您还将注意到,我编写的类检查位置更新的时间戳,并忽略任何旧的,以防止从核心位置获取过时的数据。
This is the singleton class I wrote. Please note that it is a little rough around the edges:
这是我编写的单例类。请注意边缘有点粗糙:
#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
#2
7
There is no such convenience and you shouldn't create your own. "Blocks until it gets the result" is extremely bad programming practice on a device like the iPhone. It can take seconds to retrieve a location; you should never make your users wait like that, and delegates ensure they don't.
没有这种方便,你不应该创建自己的。在iPhone这样的设备上,“阻塞直到得到结果”是极其糟糕的编程实践。检索位置可能需要几秒钟;你不应该让你的用户那样等待,委托确保他们不会。
#3
4
There are no "convenience methods" unless you code them yourself, but you'd still need to implement the delegate methods in whatever custom code you use to make things "convenient."
没有“方便方法”,除非您自己编写它们,但是您仍然需要在您使用的任何自定义代码中实现委托方法,以使事情“方便”。
The delegate pattern is there for a reason, and as delegates are a big part of Objective-C, I recommend you get comfortable with them.
委托模式的存在是有原因的,由于委托是Objective-C的重要组成部分,我建议您熟悉它们。
#4
0
I appreciated the answer by Brad Smith. Implementing it I discovered that one of the methods he employs is deprecated as of iOS6. To write code that will work with both iOS5 and iOS6, use the following:
我很欣赏布拉德·史密斯的回答。实现它时,我发现他使用的方法之一是不赞成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];
}
#5
0
I simplified and combined multiple answers to where the location is only updated if it's valid.
我简化并组合了多个答案,只有在位置有效时才更新。
It also works under OSX as well as iOS.
它也适用于OSX和iOS。
This assumes the use-case where the current location is suddenly desired by the user. If it takes more than 100 ms in this example, it's considered an error. (Assumes the GPS IC &| Wifi (Apple's Skyhook clone) is already fired up and has a good fix already.)
这假设用户突然需要当前位置的用例。如果在本例中需要超过100ms,则视为错误。(假设GPS IC和| Wifi(苹果的Skyhook克隆产品)已经启动,并且已经得到了很好的修复。)
#import "LocationManager.h"
// wait up to 100 ms
CLLocation *location = [LocationManager currentLocationByWaitingUpToMilliseconds:100];
if (!location) {
NSLog(@"no location :(");
return;
}
// location is good, yay
https://gist.github.com/6972228
https://gist.github.com/6972228