Sergey Grishchev
Sergey Grishchev

Reputation: 12051

iOS Get User Location as NSString

What I want to accomplish in my app is to get the current user location and display it onscreen in a UILabel. I would like to have an NSString of current user's location with a format similar to this: @"City, State/Country". It would be a one-time operation at the start of the app launch.

I have no prior experience with location in iOS and I would like to get some advice on this one - I'm sure it's quite a simple task.

Upvotes: 1

Views: 2221

Answers (4)

Rob
Rob

Reputation: 438467

The process is as follows:

  1. Add CoreLocation.framework to your project. See Linking to a Library or a Framework. If you want to use the address book constants that I use below, you might want to add the AddressBook.framework to your project, too.

  2. Start location services. For this purpose, the "significant change" service (less accurate, but lower power consumption) is probably sufficient for city-level accuracy.

  3. When the location manager informs you of the user's location, then perform a reverse geocode of that location.

  4. Stop location services.

Thus, that might look like:

#import <CoreLocation/CoreLocation.h>
#import <AddressBook/AddressBook.h>

@interface ViewController () <CLLocationManagerDelegate>

@property (nonatomic, strong) CLLocationManager *locationManager;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self startSignificantChangeUpdates];
}

- (void)startSignificantChangeUpdates
{
    if ([CLLocationManager locationServicesEnabled])
    {
        if (!self.locationManager)
            self.locationManager = [[CLLocationManager alloc] init];

        self.locationManager.delegate = self;
        [self.locationManager startMonitoringSignificantLocationChanges];
    }
}

- (void)stopSignificantChangesUpdates
{
    [self.locationManager stopUpdatingLocation];
    self.locationManager = nil;
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *location = [locations lastObject];

    CLGeocoder *geocoder = [[CLGeocoder alloc] init];

    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
        CLPlacemark *placemark = placemarks[0];
        NSDictionary *addressDictionary = [placemark addressDictionary];
        NSString *city = addressDictionary[(NSString *)kABPersonAddressCityKey];
        NSString *state = addressDictionary[(NSString *)kABPersonAddressStateKey];
        NSString *country = placemark.country;

        self.label.text = [NSString stringWithFormat:@"%@, %@, %@", city, state, country];
    }];

    [self stopSignificantChangesUpdates];
}

Note, the location manager's notification of the location is contingent upon the user electing to share that with your app and will happen, even in the best case scenario, asynchronously. Likewise the reverse geocode happens asynchronously.

See Getting User Location from the Location Awareness Programming Guide.

Upvotes: 8

Daniel
Daniel

Reputation: 23359

Use -reverseGeocodeLocation:completionHandler: of CLGeocoder.

Try this code snippet, the only trick is that the CLPlacemark (see the Documentation for available info) you get back from the Geocoder has a bunch of info which isn't always consistent, this was one of my tries from an older project, trying to test for location, street name etc... test with your usage case to find a good match:

- (void)getLocationStringForCoordinates:(CLLocationCoordinate2D)coordinates {

    if ( CLLocationCoordinate2DIsValid(coordinates) ) {

        CLLocation *photoLocation = [[CLLocation alloc] initWithLatitude:coordinates.latitude longitude:coordinates.longitude];
        CLGeocoder *geocoder = [[CLGeocoder alloc] init];

        [geocoder reverseGeocodeLocation:photoLocation
                       completionHandler:^(NSArray *placemarks, NSError *error) {
                           CLPlacemark *locationPlacemark = [placemarks lastObject];

                           // Location (popular name, street, area)
                           NSString *location = locationPlacemark.subLocality ? locationPlacemark.subLocality : (locationPlacemark.name ? locationPlacemark.name : locationPlacemark.thoroughfare);

                           // sometimes the location can be the same
                           // as the city name (for small villages), if so
                           // make sure location is nil to skip it
                           // else if
                           // the location name is not being used but is very short 9less then 20 letters, use that instead
                           if([locationPlacemark.name isEqualToString:locationPlacemark.locality] && [location isEqualToString:locationPlacemark.name])
                               location = @"";
                           else if ( ![locationPlacemark.name isEqualToString:location] && locationPlacemark.name.length < 20 )
                               location = locationPlacemark.name;

                           // city
                           NSString *city = locationPlacemark.subAdministrativeArea ? locationPlacemark.subAdministrativeArea : locationPlacemark.locality;

                           city = city.length > 0 ? [@", " stringByAppendingString:city] : city;

                           NSString *locationName = [NSString stringWithFormat:@"%@%@", location, city];


                       }];
    }
}

Upvotes: 2

Alex
Alex

Reputation: 1625

Take a look at the reverseGeocodeLocation:completionHandler: method for CLGeocoder:

http://developer.apple.com/library/ios/#documentation/CoreLocation/Reference/CLGeocoder_class/Reference/Reference.html#//apple_ref/doc/uid/TP40009573

First you will have to use a CLLocationManager to get a CLLocation representing the user's current position.

Upvotes: 0

Sergey Grishchev
Sergey Grishchev

Reputation: 12051

I've found a really nice and simple to follow tutorial on this topic - http://www.appcoda.com/how-to-get-current-location-iphone-user/

Hope it will be helpful to others!

Upvotes: 0

Related Questions