Skip to content

Instantly share code, notes, and snippets.

@richarddas
Forked from chrishulbert/LocationHelper.m
Created October 14, 2012 21:18
Show Gist options
  • Save richarddas/3889838 to your computer and use it in GitHub Desktop.
Save richarddas/3889838 to your computer and use it in GitHub Desktop.
Blocks location helper for finding location on an iphone
//
// LocationHelper.m
//
// Created by Chris Hulbert on 24/04/12.
// Modified by Richard Das 15/10/12.
//
#import "LocationHelper.h"
@interface LocationHelper()
@property(copy) LocationBlock locationBlock;
@property(strong) CLLocationManager* locMan;
@end
@implementation LocationHelper
@synthesize bestEffortAtLocation, locationBlock, locMan;
+ (void)getLocation:(LocationBlock)block {
if ([CLLocationManager locationServicesEnabled]) {
// We have to instantiate something so we can use it as a delegate. Boo hiss. Blocks rule!
LocationHelper* lh = [[LocationHelper alloc] init];
lh.locationBlock = block;
// Kick off the location finder
lh.locMan = [[CLLocationManager alloc] init];
lh.locMan.desiredAccuracy = kCLLocationAccuracyKilometer; // Get the roughest accuracy (eg use cell towers not gps)
lh.locMan.delegate = lh;
lh.locMan.purpose = locationHelperPurpose;
[lh.locMan startUpdatingLocation];
// This serves two purposes: keep the instance retained by the runloop, and timeout if things don't work
[lh performSelector:@selector(timeout) withObject:nil afterDelay:10.0];
} else {
block(nil); // Not enabled
}
}
// This is used to keep the instance retained by the runloop, and to call the block just in case the location manager didn't
- (void)timeout
{
if (self.locationBlock) {
self.locationBlock(nil);
self.locationBlock=nil;
}
[self.locMan stopUpdatingLocation];
self.locMan = nil;
}
#pragma mark - Delegate stuff
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if (self.locationBlock) {
// test the age of the location measurement to determine if the measurement is cached
// in most cases you will not want to rely on cached measurements
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 5.0) return;
// test that the horizontal accuracy does not indicate an invalid measurement
if (newLocation.horizontalAccuracy < 0) return;
// test the measurement to see if it is more accurate than the previous measurement
NSLog(@"LocHelper New Location accuracy: %f x %f", newLocation.horizontalAccuracy, newLocation.verticalAccuracy );
if ( self.bestEffortAtLocation == nil || self.bestEffortAtLocation.horizontalAccuracy > newLocation.horizontalAccuracy )
{
// store the location as the "best effort"
self.bestEffortAtLocation = newLocation;
if (newLocation.horizontalAccuracy <= self.locMan.desiredAccuracy)
{
// pass it on to the block
self.locationBlock(newLocation);
self.locationBlock=nil;
// we have a measurement that meets our requirements, so we can stop updating the location
[self.locMan stopUpdatingLocation];
self.locMan = nil;
// we can also cancel our previous performSelector:withObject:afterDelay: - it's no longer necessary
[NSObject cancelPreviousPerformRequestsWithTarget:manager selector:@selector(timeout) object:nil];
}
}
}
}
// If it fails,
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"Location manager failed: %@", error);
if (self.locationBlock) {
self.locationBlock(nil);
self.locationBlock=nil;
}
[self.locMan stopUpdatingLocation];
self.locMan = nil;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment