Location services using CoreLocation framework

Location Services Objective-C

In this tutorial I will show you how to use the CoreLocation framework to update location, fetching info about the received location and using their delegate methods. First what we need to make sure is that we have included NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription to the plist file.

Screen Shot 2016-05-25 at 14.20.34
When we are sure that the above is done, we can proceed with creating a separate class where we will store everything that I will write here so you can have it for future usage and reuse of the class in other projects where you will have needs of working with location services.

I would start by showing you how the interface (.h file) will look like:

#import <Foundation/Foundation.h>

@protocol locationDelegate;
@interface LocationManager : NSObject
<CLLocationManagerDelegate,UIAlertViewDelegate>

+ (id)sharedInstance;

@property(nonatomic,strong) CLLocationManager *locationManager;
@property(nonatomic,strong) CLGeocoder *geocoder;
@property(nonatomic,strong)NSString *current_country;
@property(nonatomic,strong)NSString *current_city;
@property(nonatomic,strong)NSString *country_code;
@property(nonatomic,strong)NSString *locatedAt;
@property(nonatomic)double current_latitude;
@property(nonatomic)double current_longitude;
@property(nonatomic)BOOL locationServices;
@property(nonatomic,weak)id <locationDelegate> delegate;

@end
@protocol locationDelegate <NSObject>

-(void)receivedLocation;

@end

 

Let’s now move to implementation (.m file) and make a breakdown of all the methods.

 

  1. First, we make this class singleton and initialise the location services inside the block
#import "LocationManager.h"

@implementation LocationManager
@synthesize locationManager;
@synthesize geocoder;

+ (id)sharedInstance;
{
    static dispatch_once_t onceToken;
    static LocationManager *sharedUtilsInstance = nil;
    
    dispatch_once( &onceToken, ^{
        sharedUtilsInstance = [[LocationManager alloc] init];
        [sharedUtilsInstance updateCurrentLocation];
    });
    return sharedUtilsInstance;
}

 

   2. This method triggers the location services and starts updating it (in my case I am using requestAlwaysAuthorization, but you can change it as per your needs)

-(void)updateCurrentLocation{
    locationManager = [[CLLocationManager alloc] init];
    locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
    locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
    locationManager.delegate = self;
    if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]){
        [locationManager requestAlwaysAuthorization];
    }
    [locationManager startUpdatingLocation];
}

 

3. Then we will fetch the most common fields that we might need for that location and store it in our properties

-(void)takeCurrentLocationWithCompletition:(void(^)(void))completed {
    geocoder = [[CLGeocoder alloc]init];
    [geocoder reverseGeocodeLocation:locationManager.location completionHandler:^(NSArray *placemarks, NSError *error) {
        
        if (error == nil && [placemarks count] > 0) {
            CLPlacemark *placemark = [placemarks objectAtIndex:0];
            
            self.current_country = placemark.country;
            self.locatedAt = [[placemark.addressDictionary valueForKey:@"FormattedAddressLines"] componentsJoinedByString:@","];
            self.current_city = [placemark.addressDictionary valueForKey:@"City"];
            self.country_code = [placemark.addressDictionary valueForKey:@"CountryCode"];
            self.current_latitude = locationManager.location.coordinate.latitude;
            self.current_longitude = locationManager.location.coordinate.longitude;
            if ([[self delegate] respondsToSelector:@selector(receivedLocation)]) {
                [[self delegate] receivedLocation];
            }
            
            if (completed != nil) completed();
        }
        else {
            NSLog(@"%@", error.debugDescription);
        }
    }];
}

 

4. At the end, we are going to use the delegate method didChangeAuthorizationStatus which tells us if the user approved or rejected the location services.

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
    if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways) {
        self.locationServices = YES;
        [[NSNotificationCenter defaultCenter] postNotificationName:@"WaitingLocation" object:nil];
        [self takeCurrentLocationWithCompletition:nil];
    }
    else if (status == kCLAuthorizationStatusDenied){
        NSString *locationOpened = [[NSUserDefaults standardUserDefaults] valueForKey:@"locationView"];
        if (locationOpened == nil || [locationOpened isEqualToString:@"0"]) {
            UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"Location Service Disabled" message:@"To re-enable, please go to Settings and turn on Location Service for this app, otherwise you will be given the last 50 posts worldwide." delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:@"Settings", nil];
            [av show];
            NSLog(@"Denied Location Services!");
        }
        else{
            [[NSNotificationCenter defaultCenter] postNotificationName:@"RefreshLocation" object:self];
            self.locationServices = NO;
        }
    }
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    if (buttonIndex == 1) {
        NSURL *settings = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
        if ([[UIApplication sharedApplication] canOpenURL:settings]){
            [[UIApplication sharedApplication] openURL:settings];
        }
    }
    else{
        [[NSNotificationCenter defaultCenter] postNotificationName:@"RefreshLocation" object:self];
    }
}

@end

Usage:

I suggest using [LocationManager sharedInstance] in AppDelegate which will trigger and update every method in the LocationManager class. After everything is populated you can easily use all properties at the desired places around the project. 

 

Leave a Reply

Your email address will not be published. Required fields are marked *