-
-
Save richarddas/3889838 to your computer and use it in GitHub Desktop.
Blocks location helper for finding location on an iphone
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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