Viny76 Viny76 - 4 months ago 37
Objective-C Question

iOS Geofencing with CoreLocation

I would like to know when user are near my home.
I'm using CoreLocation, and would like to always know if user is near my home (around 100m) even if the app is closed.

For this, I succeed in my code to know if the user is around 100m (with

works fine too. I'm using
in order to localize user.

I would like to save battery life, so I added
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
to update location after user makes 3km.

Tell me how can I save more battery life, and how can I update location even if app is in background/closed (maybe I've to change something in my AppDelegate) ?

And I would like to know if my code will work for my needs ?

Here is my code :

#import "ViewController.h"
@import UserNotifications;

@interface ViewController ()


@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;

// Request Notification
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert)
completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!error) {
NSLog(@"request authorization succeeded!");

- (void)setUpGeofences {
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(49.451096,
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center
[self.locationManager startMonitoringForRegion:region];
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
self.locationManager.allowsBackgroundLocationUpdates = YES;

- (void)showSorryAlert {
UIAlertController *alert = [UIAlertController
message:@"You are using UIAlertController"
[self presentViewController:alert animated:YES completion:nil];

- (void)locationManager:(CLLocationManager *)manager
didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
switch (status) {
case kCLAuthorizationStatusNotDetermined:
[self.locationManager requestAlwaysAuthorization];
case kCLAuthorizationStatusAuthorizedWhenInUse:
[self.locationManager startUpdatingLocation];
[self setUpGeofences];
case kCLAuthorizationStatusAuthorizedAlways:
[self.locationManager startUpdatingLocation];
[self setUpGeofences];
case kCLAuthorizationStatusRestricted:
// restricted by e.g. parental controls. User can't enable Location Services
case kCLAuthorizationStatusDenied:
// user denied your app access to Location Services, but can grant access from

- (void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLRegion *)region {
NSLog(@"didEnter : %@", region);
[self displayNotif:@"Bienvenue !" withBody:@"Passez nous voir !"];

- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
[self displayNotif:@"Au revoir !" withBody:@"A bientôt !"];

- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
NSLog(@"Start monitoring for region: %@", region.identifier);
[self.locationManager requestStateForRegion:region];

- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
NSLog(@"Error: %@", error);

- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
// Stop location updates when they aren't needed anymore
[self.locationManager stopUpdatingLocation];

// Disable background location updates when they aren't needed anymore
self.locationManager.allowsBackgroundLocationUpdates = NO;

- (void)locationManager:(CLLocationManager *)manager
didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
// When regions are initialized, see if we are already within the geofence.
switch (state) {
case CLRegionStateInside: [self displayNotif:@"Bienvenue" withBody:@"Passez nous voir !"];
case CLRegionStateUnknown: NSLog(@"Unknown");
case CLRegionStateOutside: NSLog(@"Outside");
default: break;

- (void)displayNotif:(NSString *)title withBody:(NSString *)body {
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:title arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:body
content.sound = [UNNotificationSound defaultSound];

/// 4. update application icon badge number
content.badge = @([[UIApplication sharedApplication] applicationIconBadgeNumber] + 1);
// Deliver the notification in five seconds.
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger
triggerWithTimeInterval:1.f repeats:NO];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"OneSecond"
content:content trigger:trigger];
/// 3. schedule localNotification
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (!error) {
NSLog(@"add NotificationRequest succeeded!");



Regarding your issue about monitoring in the background, please refer to Apples documentation, it states the following:

If a region boundary is crossed while an app isn’t running, that app is relaunched into the background to handle the event. Similarly, if the app is suspended when the event occurs, it’s woken up and given a short amount of time (around 10 seconds) to handle the event.

This means, as long as your authorizationStatus is set to .authorizedAlways then the rest will take care of it'self automatically.

link to rest of docs: