Skip to content

Instantly share code, notes, and snippets.

@keicoder
Created March 2, 2014 06:32
Show Gist options
  • Save keicoder/9302772 to your computer and use it in GitHub Desktop.
Save keicoder/9302772 to your computer and use it in GitHub Desktop.
objective-c : getting locaton
//getting locaton
//1. MyLocations Project Settings
//use tab bar controller
//import CoreLocation.framework
//CurrentLocationViewController.h
#import <CoreLocation/CoreLocation.h>
@interface CurrentLocationViewController : UIViewController <CLLocationManagerDelegate>
@property (nonatomic, weak) IBOutlet UILabel *messageLabel;
@property (nonatomic, weak) IBOutlet UILabel *latitudeLabel;
@property (nonatomic, weak) IBOutlet UILabel *longitudeLabel;
@property (nonatomic, weak) IBOutlet UILabel *addressLabel;
@property (nonatomic, weak) IBOutlet UIButton *tagButton;
@property (nonatomic, weak) IBOutlet UIButton *getButton;
- (IBAction)getLocation:(id)sender;
@end
//CurrentLocationViewController.m
@implementation CurrentLocationViewController
{
CLLocationManager *_locationManager; //CLLocationManager give you the GPS coordinates
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder])) {
_locationManager = [[CLLocationManager alloc] init];
// For testing. Uncomment this line to use any location you want,
// without having to use the Simulator's Location menu.
//_location = [[CLLocation alloc] initWithLatitude:37.785834 longitude:-122.406417];
}
return self;
}
//hooked up to the Get My Location button
- (IBAction)getLocation:(id)sender
{
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; //accuracy of up to ten meters
[_locationManager startUpdatingLocation]; ////Starts the generation of updates that report the user’s current location
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"didFailWithError %@", error);
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = [locations lastObject];
NSLog(@"didUpdateLocations %@", newLocation);
}
//2. Putting the coordinates on the screen
//FirstViewController.m
@implementation CurrentLocationViewController
{
CLLocationManager *_locationManager;
CLLocation *_location; //store the user’s current location in this variable
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = [locations lastObject];
NSLog(@"didUpdateLocations %@", newLocation);
_location = newLocation;
[self updateLabels];
}
- (void)updateLabels
{
if (_location != nil) {
self.latitudeLabel.text = [NSString stringWithFormat:
@"%.8f", _location.coordinate.latitude]; //.8 means 8 digits behind the decimal point
self.longitudeLabel.text = [NSString stringWithFormat:
@"%.8f", _location.coordinate.longitude];
self.tagButton.hidden = NO;
self.messageLabel.text = @"";
} else {
// Initially, the screen should say, “Press the Button to Start” and the latitude and longitude labels are empty
self.latitudeLabel.text = @"";
self.longitudeLabel.text = @"";
self.addressLabel.text = @"";
self.tagButton.hidden = YES;
self.messageLabel.text = @"Press the Button to Start";
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self updateLabels];
}
//3. Handling errors
//CurrentLocationViewController.m
@implementation CurrentLocationViewController
{
CLLocationManager *_locationManager;
CLLocation *_location; //store the user’s current location in this variable
BOOL _updatingLocation; //boolean, If it is NO, then location manager wasn’t currently active and there’s no need to stop it
NSError *_lastLocationError;
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"didFailWithError %@", error);
// The kCLErrorLocationUnknown error means the location manager was unable
// to obtain a location right now. We will keep trying until we do find a
// location or receive a more serious error.
// Some of the Core Location errors:
// kCLErrorLocationUnknown - The location is currently unknown, but Core Location will keep trying.
// kCLErrorDenied - The user declined the app to use location services.
// kCLErrorNetwork - There was a network-related error
if (error.code == kCLErrorLocationUnknown) {
return;
}
[self stopLocationManager];
_lastLocationError = error;
[self updateLabels];
[self configureGetButton];
}
- (void)stopLocationManager
{
if (_updatingLocation) {
// Tell the location manager we no longer want to receive updates.
[_locationManager stopUpdatingLocation];
_locationManager.delegate = nil;
_updatingLocation = NO;
}
}
- (void)updateLabels
{
// If we have a location object then we will always show its coordinates,
// even if we're still fetching a more accurate location at the same time.
if (_location != nil) {
self.latitudeLabel.text = [NSString stringWithFormat:@"%.8f", _location.coordinate.latitude];
self.longitudeLabel.text = [NSString stringWithFormat:@"%.8f", _location.coordinate.longitude];
self.tagButton.hidden = NO;
self.messageLabel.text = @"";
// If we have no location yet, then we're either waiting for the user to
// press the button to start, still get our first location fix, or we ran
// into an error situation.
} else {
self.latitudeLabel.text = @"";
self.longitudeLabel.text = @"";
self.addressLabel.text = @"";
self.tagButton.hidden = YES;
//If the location manager gave an error, the label will show an error message
NSString *statusMessage;
if (_lastLocationError != nil) {
if ([_lastLocationError.domain isEqualToString:kCLErrorDomain] && _lastLocationError.code == kCLErrorDenied) {
statusMessage = @"Location Services Disabled";
} else {
statusMessage = @"Error Getting Location";
}
} else if (![CLLocationManager locationServicesEnabled]) {
statusMessage = @"Location Services Disabled";
} else if (_updatingLocation) {
statusMessage = @"Searching...";
} else {
statusMessage = @"Press the Button to Start";
}
self.messageLabel.text = statusMessage;
}
}
//move getLocation action into its own startLocationManager method
- (void)startLocationManager
{
if ([CLLocationManager locationServicesEnabled]) { //locationServicesEnabled : Returns a Boolean value indicating whether location services are enabled on the device.
// Tell the location manager to start fetching the location.
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[_locationManager startUpdatingLocation]; ////Starts the generation of updates that report the user’s current location
_updatingLocation = YES;
}
}
//Change the getLocation method to
- (IBAction)getLocation:(id)sender
{
[self startLocationManager];
[self updateLabels];
}
//change didUpdateLocations method
//in case there was an error and no location could be obtained
//but walk around for a bit and a valid location comes in
//in that case wipe the old error code
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = [locations lastObject];
NSLog(@"didUpdateLocations %@", newLocation);
_lastLocationError = nil; _location = newLocation;
[self updateLabels];
}
//4. Improving the results
//CurrentLocationViewController.m
//stop getting location updates, when the location is accurate enough
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = [locations lastObject];
NSLog(@"didUpdateLocations %@", newLocation);
// If the time at which the new location object was determined is too long
// ago (5 seconds in this case), then this is a cached result. ignore
// these cached locations because they may be out of date.
if ([newLocation.timestamp timeIntervalSinceNow] < -5.0) {
//timestamp : The time at which location was determined
return;
}
// Ignore invalid measurements.
if (newLocation.horizontalAccuracy < 0) {
return;
}
// Only perform the following code if the new location provides a more
// precise reading than the previous one, or if it's the very first.
// _location is nil means this is the very first location update
if (_location == nil || _location.horizontalAccuracy > newLocation.horizontalAccuracy) {
// Put the new coordinates on the screen.
_lastLocationError = nil;
_location = newLocation;
[self updateLabels];
// We're done if the new location is accurate enough.
if (newLocation.horizontalAccuracy <= _locationManager.desiredAccuracy) {
NSLog(@"*** We're done!");
[self stopLocationManager];
}
}
}
//change the state of button
- (void)configureGetButton
{
if (_updatingLocation) {
[self.getButton setTitle:@"Stop" forState:UIControlStateNormal];
} else {
[self.getButton setTitle:@"Get My Location" forState:UIControlStateNormal];
}
}
//call the configureGetButton method
- (void)viewDidLoad {
[super viewDidLoad];
[self updateLabels];
[self configureGetButton];
}
- (IBAction)getLocation:(id)sender {
[self startLocationManager]; [self updateLabels];
[self configureGetButton];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
//...
[self updateLabels];
[self configureGetButton];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
//...
if (newLocation.horizontalAccuracy <= _locationManager.desiredAccuracy) {
NSLog(@"*** We're done!");
[self stopLocationManager];
[self configureGetButton];
}
}
}
- (IBAction)getLocation:(id)sender
{
if (_updatingLocation) { //_updatingLocation flag to determine what state the app is in
[self stopLocationManager];
} else {
_location = nil;
_lastLocationError = nil;
_placemark = nil;
_lastGeocodingError = nil;
[self startLocationManager];
}
[self updateLabels];
[self configureGetButton];
}
//5. Reverse Geocoding (using CLGeocoder)
//CLGeocoder object to turn the location data into a human-readable address
//CurrentLocationViewController.m
//add the following instance variables
@implementation CurrentLocationViewController
{
CLGeocoder *_geocoder;
CLPlacemark *_placemark; //Placemark data includes information such as the country, state, city, and street address
BOOL _performingReverseGeocoding;
NSError *_lastGeocodingError;
}
//create the geocoder object
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder])) {
//...
_geocoder = [[CLGeocoder alloc] init];
}
return self;
}
//put the geocoder to work
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
//...
if (_location == nil || _location.horizontalAccuracy > newLocation.horizontalAccuracy) {
//...
if (newLocation.horizontalAccuracy <= _locationManager.desiredAccuracy) {
//...
if (!_performingReverseGeocoding) {
NSLog(@"*** Going to geocode");
// Unlike the location manager, CLGeocoder does not use a delegate to tell you about the result,
// but something called a block.
// Start a new reverse geocoding request and update the screen
// with the results (a new placemark or error message).
_performingReverseGeocoding = YES;
[_geocoder reverseGeocodeLocation:_location completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(@"*** Found placemarks: %@, error: %@", placemarks, error);
_lastGeocodingError = error;
if (error == nil && [placemarks count] > 0) {
_placemark = [placemarks lastObject]; //Placemark data includes information such as the country, state, city, and street address
} else {
_placemark = nil;
}
_performingReverseGeocoding = NO;
[self updateLabels];
}];
}
}
}
//make the address visible to the user
//Change updateLabels
- (void)updateLabels
{
// If we have a location object then we will always show its coordinates,
// even if we're still fetching a more accurate location at the same time.
if (_location != nil) {
//...
// Once we have a location, we try to reverse geocode it and show the
// results in the address label.
if (_placemark != nil) {
self.addressLabel.text = [self stringFromPlacemark:_placemark];
} else if (_performingReverseGeocoding) {
self.addressLabel.text = @"Searching for Address...";
} else if (_lastGeocodingError != nil) {
self.addressLabel.text = @"Error Finding Address";
} else {
self.addressLabel.text = @"No Address Found";
}
// If we have no location yet, then we're either waiting for the user to
// press the button to start, still get our first location fix, or we ran
// into an error situation.
} else {
//...
}
}
//Add the stringFromPlacemark:
- (NSString *)stringFromPlacemark:(CLPlacemark *)thePlacemark
{
return [NSString stringWithFormat:@"%@ %@\n%@ %@ %@",
thePlacemark.subThoroughfare, thePlacemark.thoroughfare,
thePlacemark.locality, thePlacemark.administrativeArea,
thePlacemark.postalCode];
//subThoroughfare: Additional street-level information for the placemark
//thoroughfare: The street address associated with the placemark
//locality: The city associated with the placemark
//administrativeArea: The state or province associated with the placemark
//postalCode: The postal code associated with the placemark
}
//in getLocation, clear out the _placemark and _lastGeocodingError variables
//in order to start with a clean slate
- (IBAction)getLocation:(id)sender
{
if (_updatingLocation) {
[self stopLocationManager];
} else {
_location = nil;
_lastLocationError = nil;
_placemark = nil;
_lastGeocodingError = nil;
[self startLocationManager];
}
[self updateLabels];
[self configureGetButton];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment