iOS6 multithreading with CLLocationManager (how not to delay main thread) - ios

I have a question about multithreading in iOS6.
I make app, that starts and stops CLLocationManager, when user press the UISwitch.
I start CLLocationManager in separate thread (I don't want user seen any delay in main thread) , but sometimes UISwitch didn't change it's value. Delay occurs. I think it is because of starting CLLocationManager. Why it happens? I thought, that if I use threading, there will be no delay in main thread.
The code:
- (IBAction)useGPS:(UISwitch *)sender {
if (![trackLocationSwitch isOn]) {
[useGPSSwitch setOn:NO];
return;
}
if ([sender isOn]) {
[accuracyLabel setText:#"Satellite"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
[trackLocation startTrackLocationUsingOnlyGPS:YES];
});
} else {
[accuracyLabel setText:#"Cellular"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
[trackLocation stopTrackLocation];
[trackLocation startTrackLocationUsingOnlyGPS:NO];
});
}
TrackLocation.m:
- (void)startTrackLocationUsingOnlyGPS:(BOOL)useOnlyGPS {
if ( useOnlyGPS ) {
[self restartLocationManagerWithBestAccuracy:YES];
useBestAccuracy = YES;
onlyGPS = YES;
} else {
[self restartLocationManagerWithBestAccuracy:NO];
useBestAccuracy = NO;
onlyGPS = NO;
}
- (void)stopTrackLocation {
[locationManager stopUpdatingLocation];
[locationManager stopMonitoringSignificantLocationChanges];
}
- (void)restartLocationManagerWithBestAccuracy:(BOOL)_useBestAccuracy {
if ( _useBestAccuracy ) {
useBestAccuracy = YES;
[locationManager stopUpdatingLocation];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locationManager setPausesLocationUpdatesAutomatically:NO];
[locationManager setActivityType:CLActivityTypeFitness];
[locationManager setDistanceFilter:100];
[locationManager startUpdatingLocation];
} else {
useBestAccuracy = NO;
[locationManager stopUpdatingLocation];
[locationManager startMonitoringSignificantLocationChanges];
}
}

Related

iOS app background location access using a timer

I am looking for a solution to access/stop location services while app is in the background. My app takes continuous location when it's sent to background (It has access to continuous location) . It's necessary for the app functionality.
So I would like to know few things:
How long my app can take continuous location while it's still in the background? (before OS kills the background process or something like that)
If I want to add a timer say after 60 minutes app will stop taking the location, what would be the correct approach?
Background location updation can be done using following code:
In Appdelegate class:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
// This "afterResume" flag is just to show that he receiving location updates
// are actually from the key "UIApplicationLaunchOptionsLocationKey"
self.shareModel.afterResume = YES;
[self.shareModel startMonitoringLocation];
}
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
[self.shareModel stopContinuosLocationUpdate];
[self.shareModel restartMonitoringLocation];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
//Remove the "afterResume" Flag after the app is active again.
self.shareModel.afterResume = NO;
[self.shareModel startContinuosLocationUpdate];
}
In Location update class, say LocationManager.m:
#import <CoreLocation/CoreLocation.h>
#property (nonatomic) CLLocationManager * anotherLocationManager;
- (void)startContinuosLocationUpdate
{
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusDenied)
{
NSLog(#"Location services are disabled in settings.");
}
else
{
// for iOS 8
if ([self.anotherLocationManager respondsToSelector:#selector(requestAlwaysAuthorization)])
{
[self.anotherLocationManager requestAlwaysAuthorization];
}
// for iOS 9
if ([self.anotherLocationManager respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)])
{
[self.anotherLocationManager setAllowsBackgroundLocationUpdates:YES];
}
[self.anotherLocationManager startUpdatingLocation];
}
}
- (void)stopContinuosLocationUpdate
{
[self.anotherLocationManager stopUpdatingLocation];
}
- (void)startMonitoringLocation
{
if (_anotherLocationManager)
[_anotherLocationManager stopMonitoringSignificantLocationChanges];
self.anotherLocationManager = [[CLLocationManager alloc]init];
_anotherLocationManager.delegate = self;
_anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
_anotherLocationManager.activityType = CLActivityTypeOtherNavigation;
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"9.0")) {
[_anotherLocationManager setAllowsBackgroundLocationUpdates:YES];
}
else if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
[_anotherLocationManager requestAlwaysAuthorization];
}
[_anotherLocationManager startMonitoringSignificantLocationChanges];
}
- (void)restartMonitoringLocation
{
[_anotherLocationManager stopMonitoringSignificantLocationChanges];
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"9.0")) {
[_anotherLocationManager setAllowsBackgroundLocationUpdates:YES];
}
else if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
[_anotherLocationManager requestAlwaysAuthorization];
}
[_anotherLocationManager startMonitoringSignificantLocationChanges];
}
#pragma mark - CLLocationManager Delegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
if(_dictLocation && [_dictLocation isKindOfClass:[NSDictionary class]])
{
float latitudeValue = [[RVCommon validateDataForNumber:_dictLocation[#"lat"]] floatValue];
float longitudeValue = [[RVCommon validateDataForNumber:_dictLocation[#"lng"]] floatValue];
CLLocation *facilityLocation = [[CLLocation alloc] initWithLatitude:latitudeValue longitude:longitudeValue];
CLLocation *mostRecentLocation = locations.lastObject;
CLLocationDistance distanceInMeters = [mostRecentLocation distanceFromLocation:facilityLocation];
if (distanceInMeters <= 500.0)
{
//Here I am informing the server when user is within 500mts of the coordinate.
}
}
NSLog(#"locationManager didUpdateLocations: %#",locations);
}

iOS Location Updates not trigerred consistently in background mode

Requirement:
To Trigger Location update Callback after every second when the app is in background.
Problem:
Location Callbacks are not triggered after every second. Instead we get them inconsistently sometimes after 1 second, sometimes after 4 second and even with gap of 40-50 seconds.
Current Implementation:
setActivityType = CLActivityTypeOther
setAllowsBackgroundLocationUpdates = YES
setDesiredAccuracy = kCLLocationAccuracyBestForNavigation
setDistanceFilter = kCLDistanceFilterNone
setPausesLocationUpdatesAutomatically = false
plist configuration also done for background location updates.
Please suggest what more can be done to achieve solution for this problem?
Try out below code for background location updation when a significant location change is occured:
#pragma mark - CLLocationManager
- (void)startContinuosLocationUpdate
{
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusDenied)
{
NSLog(#"Location services are disabled in settings.");
}
else
{
// for iOS 8
if ([self.anotherLocationManager respondsToSelector:#selector(requestAlwaysAuthorization)])
{
[self.anotherLocationManager requestAlwaysAuthorization];
}
// for iOS 9
if ([self.anotherLocationManager respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)])
{
[self.anotherLocationManager setAllowsBackgroundLocationUpdates:YES];
}
[self.anotherLocationManager startUpdatingLocation];
}
}
- (void)stopContinuosLocationUpdate
{
[self.anotherLocationManager stopUpdatingLocation];
}
- (void)startMonitoringLocation
{
if (_anotherLocationManager)
[_anotherLocationManager stopMonitoringSignificantLocationChanges];
self.anotherLocationManager = [[CLLocationManager alloc]init];
_anotherLocationManager.delegate = self;
_anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
_anotherLocationManager.activityType = CLActivityTypeOtherNavigation;
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"9.0")) {
[_anotherLocationManager setAllowsBackgroundLocationUpdates:YES];
}
else if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
[_anotherLocationManager requestAlwaysAuthorization];
}
[_anotherLocationManager startMonitoringSignificantLocationChanges];
}
- (void)restartMonitoringLocation
{
[_anotherLocationManager stopMonitoringSignificantLocationChanges];
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"9.0")) {
[_anotherLocationManager setAllowsBackgroundLocationUpdates:YES];
}
else if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
[_anotherLocationManager requestAlwaysAuthorization];
}
[_anotherLocationManager startMonitoringSignificantLocationChanges];
}

Continuous location details when app is killed/Terminated

How to get continuous location details when app is killed/Terminated ? startMonitoringSignificantLocationChanges method firing the didUpdateLocations delegate method after 500 meters. But i want location updates in kill mode for every 10 meters. Or i want to relaunch the application in background automatically and start the location updates in background.Currently i have the working code in background.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
[[LocationManager sharedLocarionManager] updateAccuracy:YES];
[[LocationManager sharedLocarionManager].locationManager requestAlwaysAuthorization];
[[LocationManager sharedLocarionManager].locationManager stopUpdatingLocation];
[[LocationManager sharedLocarionManager].locationManager startUpdatingLocation];
[[LocationManager sharedLocarionManager].locationManager stopMonitoringSignificantLocationChanges];
[[LocationManager sharedLocarionManager].locationManager startMonitoringSignificantLocationChanges];
}
return YES;
}
LocationManager.m
- (id)init {
self = [super init];
if(self != nil) {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.locationManager.distanceFilter = 100; // meters
self.locationManager.delegate = self;
}
return self;
}
-(void)updateAccuracy:(BOOL)trackingAccuracy {
if (trackingAccuracy) {
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = 10.0 ; // meters
self.locationManager.allowsBackgroundLocationUpdates = YES;
} else {
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.locationManager.distanceFilter = 100; // meters
}
[ self.locationManager startUpdatingLocation];
[self.locationManager startMonitoringSignificantLocationChanges];
}
There is a work around. Though you cannot get continuous location when your app is killed but you can send silent push notification via server to your user to get the update about its location. You will get 30 second window when the app receives silent push notification. In that short time span, you have to perform your task.

significant change location delegate methods not being called

All of my code is in AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
_locationMgr = [[CLLocationManager alloc] init];
[_locationMgr setDelegate:self];
if([_locationMgr respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)])
[_locationMgr setAllowsBackgroundLocationUpdates:YES];
CLAuthorizationStatus authorizationStatus= [CLLocationManager authorizationStatus];
if([launchOptions valueForKey:UIApplicationLaunchOptionsLocationKey] != nil) {
NSLog(#"relaunching because of significant location change - restarting SLC");
[_locationMgr startMonitoringSignificantLocationChanges];
}
else
{
if (authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) {
NSLog(#"launching with authorization to always use location - starting SLC");
[_locationMgr startMonitoringSignificantLocationChanges];
}
else
{
NSLog(#"launching with no authorization to always use location - requesting authorization");
if([_locationMgr respondsToSelector:#selector(requestAlwaysAuthorization)])
[_locationMgr requestAlwaysAuthorization];
}
}
if([userdefaults objectForKey:#"pfuser"] == nil) {
NSLog(#"in delegate signup");
SignUpController *signup = [[SignUpController alloc] init];
[self.window setRootViewController:signup];
}
else {
ViewController *map = [[ViewController alloc] init];
[self.window setRootViewController:map];
}
[self.window makeKeyAndVisible];
return YES;
}
- (void)startSignificantChangeUpdates
{
deviceNotFoundAlertController = [UIAlertController alertControllerWithTitle:#"START" message:#"startSignificantChangeUpdates called" preferredStyle:UIAlertControllerStyleAlert];
[deviceNotFoundAlertController addAction:deviceNotFoundAlert];
// Create the location manager if this object does not
// already have one.
if (nil == _locationMgr) {
_locationMgr = [[CLLocationManager alloc] init];
_locationMgr.delegate = self;
}
[CLLocationManager significantLocationChangeMonitoringAvailable];
[_locationMgr startMonitoringSignificantLocationChanges];
}
-(void)locationManger:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"didFailWithError: %#", error);
deviceNotFoundAlertController = [UIAlertController alertControllerWithTitle:#"LOCATION FAIL" message:#"didFailWithError" preferredStyle:UIAlertControllerStyleAlert];
[deviceNotFoundAlertController addAction:deviceNotFoundAlert];
}
// Delegate method from the CLLocationManagerDelegate protocol.
- (void)_locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
deviceNotFoundAlertController = [UIAlertController alertControllerWithTitle:#"LOCATION UPDATE" message:#"didUpdateLocations called" preferredStyle:UIAlertControllerStyleAlert];
[deviceNotFoundAlertController addAction:deviceNotFoundAlert];
// If it's a relatively recent event, turn off updates to save power.
CLLocation* location = [locations lastObject];
NSDate* eventDate = location.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (fabs(howRecent) < 15.0) {
// If the event is recent, do something with it.
NSLog(#"latitude %+.6f, longitude %+.6f\n",
location.coordinate.latitude,
location.coordinate.longitude);
}
}
None of the alerts happen, it seems like the delegate methods aren't being called.
UPDATE
Now I have:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
deviceNotFoundAlert = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:nil];
...
}
// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
deviceNotFoundAlertController = [UIAlertController alertControllerWithTitle:#"LOCATION UPDATE" message:#"didUpdateLocations called" preferredStyle:UIAlertControllerStyleAlert];
[deviceNotFoundAlertController addAction:deviceNotFoundAlert];
// If it's a relatively recent event, turn off updates to save power.
CLLocation* location = [locations lastObject];
NSDate* eventDate = location.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (fabs(howRecent) < 15.0) {
// If the event is recent, do something with it.
NSLog(#"latitude %+.6f, longitude %+.6f\n",
location.coordinate.latitude,
location.coordinate.longitude);
}
}
When I test the app, I open it at my house, and then close it, so that when I leave my house it should send an alert (or 3) at some point, but I am not getting alerts from any of the delegate methods (where I placed alerts).
I just had an idea, maybe I have to display the alerts from the main UIViewController, not the AppDelegate?
This may be why I am not seeing the alerts: How do I add a UIAlertController in app delegate (obj-c)
UPDATE
This is how I am doing the alerts now:
deviceNotFoundAlertController = [UIAlertController alertControllerWithTitle:#"START" message:#"startSignificantChangeUpdates called" preferredStyle:UIAlertControllerStyleAlert];
[deviceNotFoundAlertController addAction:deviceNotFoundAlert];
alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
alertWindow.rootViewController = [[UIViewController alloc] init];
alertWindow.windowLevel = UIWindowLevelAlert + 1;
[alertWindow makeKeyAndVisible];
[alertWindow.rootViewController presentViewController:deviceNotFoundAlertController animated:YES completion:nil];
UPDATE
The alerts did not seem to be the issue, the alert in startSignificantChangeUpdates never appears. Should it appear once I am 500m from my initial location?
UPDATE
Can anyone help me understand this?
The methods of your delegate object are called from the thread in which you started the corresponding location services. That thread must itself have an active run loop, like the one found in your application’s main thread.
UPDATE
I think I figured out what the above quote is saying...and I have this now - I will test tomorrow.
...
if([launchOptions valueForKey:UIApplicationLaunchOptionsLocationKey] != nil) {
NSLog(#"relaunching because of significant location change - restarting SLC");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[_locationMgr startMonitoringSignificantLocationChanges];
});
}
else
{
if (authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) {
NSLog(#"launching with authorization to always use location - starting SLC");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[_locationMgr startMonitoringSignificantLocationChanges];
});
}
else
{
NSLog(#"launching with no authorization to always use location - requesting authorization");
if([_locationMgr respondsToSelector:#selector(requestAlwaysAuthorization)])
[_locationMgr requestAlwaysAuthorization];
}
}
...
I think that code is starting the location services on its own thread. One thing I noticed already, is that when I exit the app, the location in the top right goes away. I just updated to iOS 10. In iOS 9 the location arrow in the top right would stay there, but it would only be a black outline when the app was not running. This could just be something they changed with iOS 10, or now because I updated to 10, something else isn't working now. Or that is what happens when the location services are run on their own thread. From here: iOS start Background Thread
UPDATE
Maybe I am not using the thread correctly, but as I said, now when I close the app, location services quits. When I was doing it without the thread the location service arrow would stay in the top right, as an outline.
UPDATE
I read that the service should be started on the main thread - so now I have:
CLAuthorizationStatus authorizationStatus= [CLLocationManager authorizationStatus];
NSLog(#"launching with no authorization to always use location - requesting authorization");
if([_locationMgr respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[_locationMgr requestAlwaysAuthorization];
}
if([launchOptions valueForKey:UIApplicationLaunchOptionsLocationKey] != nil) {
NSLog(#"relaunching because of significant location change - restarting SLC");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[_locationMgr startMonitoringSignificantLocationChanges];
});
}
else if (authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) {
NSLog(#"launching with authorization to always use location - starting SLC");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[_locationMgr startMonitoringSignificantLocationChanges];
});
}
else {
//
}
The arrow in the right doesn't show up when the app is closed, is this something new to iOS 10 where they don't show it anymore?
UPDATE
I accidentally deleted: _locationMgr = [[CLLocationManager alloc] init]; I put in and now the arrow is always there, going to test today.
UPDATE
I tested it, still no alerts.
It is a problem with your delegate method please replace below one
- (void)_locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
}
with
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
}
Hope it will help you.
I took my computer with me in my car, and watched the console, and I saw that the significant location changes are happening now because I get location updates every 500m. The alerts are the only thing not working, but they are irrelevant to the program - they were just there to see if it was working. It is working with this code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
...
_locationMgr = [[CLLocationManager alloc] init];
[_locationMgr setDelegate:self];
if([_locationMgr respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)])
[_locationMgr setAllowsBackgroundLocationUpdates:YES];
CLAuthorizationStatus authorizationStatus= [CLLocationManager authorizationStatus];
NSLog(#"launching with no authorization to always use location - requesting authorization");
if([_locationMgr respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[_locationMgr requestAlwaysAuthorization];
}
if([launchOptions valueForKey:UIApplicationLaunchOptionsLocationKey] != nil) {
NSLog(#"relaunching because of significant location change - restarting SLC");
[_locationMgr startMonitoringSignificantLocationChanges];
}
else if (authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) {
NSLog(#"launching with authorization to always use location - starting SLC");
[_locationMgr startMonitoringSignificantLocationChanges];
}
else {
//
}
...
[self.window makeKeyAndVisible];
return YES;
}
- (void)startSignificantChangeUpdates
{
// Create the location manager if this object does not
// already have one.
if (nil == _locationMgr) {
_locationMgr = [[CLLocationManager alloc] init];
_locationMgr.delegate = self;
}
[CLLocationManager significantLocationChangeMonitoringAvailable];
[_locationMgr startMonitoringSignificantLocationChanges];
deviceNotFoundAlertController = [UIAlertController alertControllerWithTitle:#"START" message:#"startSignificantChangeUpdates called" preferredStyle:UIAlertControllerStyleAlert];
}
-(void)locationManger:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"didFailWithError: %#", error);
}
// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
// If it's a relatively recent event, turn off updates to save power.
CLLocation* location = [locations lastObject];
NSDate* eventDate = location.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (fabs(howRecent) < 15.0) {
// If the event is recent, do something with it.
NSLog(#"latitude %+.6f, longitude %+.6f\n",
location.coordinate.latitude,
location.coordinate.longitude);
}
}
You have written write code, Just add below delegate method in your code. But startMonitoringSignificantLocationChanges for updating location take 10 to 20 min. and also trigger if location channel change.
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
}
[_locationMgr startMonitoringSignificantLocationChanges];
The significant-change location service delivers updates only when there has been a significant change in the device’s location, such as 500 meters or more.
So your delegate method will call each time once when your device moved more than 500 meter.
Make sure your app have background location permission.
if your app is in background or foreground then it will call delegate method
otherwise app will launch with location option in AppDelegate file where you have to create Location manager object and start location again to get new location.
https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html

How to solve the issue with beacon?

My Problem: When I click the button, my phone will show a progress view(ask me come close the beacon), and when I come close the beacon, my phone will show a view(checkmark), and then remove the view 1.5s later. Now the view can show normally first, but when I take my phone far away from the beacon, and the view(show checkmark) will show 1s later. It's a big problem out of my mind.
My code:
onClick button
- (IBAction)chooseBLEAction:(id)sender {
self.locationManager = [CLLocationManager new];
[self _initBeaconRegion];
if (([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse ||
[CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways ||
[CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) &&
[self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)])
{
[self _start];
if (self.bluetoothIsOpen) {
[self _createProgressView];
}
}else {
[self.locationManager requestWhenInUseAuthorization];
}
}
- (void)_start {
[self.locationManager startRangingBeaconsInRegion:self.targetBeaconRegion];
}
- (void)_stop {
[self.locationManager stopRangingBeaconsInRegion:self.targetBeaconRegion];
}
CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray<CLBeacon *> *)beacons inRegion:(CLBeaconRegion *)region {
NSLog(#"searching for beacon !");
CLBeacon *foundBeacon = [CLBeacon new];
foundBeacon = [beacons firstObject];
if (foundBeacon) {
NSLog(#"found beacon !");
switch (foundBeacon.proximity) {
case CLProximityUnknown:
break;
case CLProximityFar:
break;
case CLProximityNear:
break;
case CLProximityImmediate:
{
[self _stop];
NSLog(#"Immediate beacon !");
AudioServicesPlaySystemSound(1051);
[self.myProgressView removeFromSuperview];
[self _createSuceessProgressView];
self.removeProgressViewTimer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:#selector(_removeSuccessProgressView) userInfo:nil repeats:NO];
break;
}
}
}
}
create progress view (close the beacon)
- (void)_createProgressView {
NSString *title = #"Please close the beacon";
self.myProgressView = [MRProgressOverlayView showOverlayAddedTo:self.view title:title mode:MRProgressOverlayViewModeIndeterminate animated:YES];
}
create success view
- (void)_createSuceessProgressView {
NSString *title = #"Success!";
self.suceessProgressView = [MRProgressOverlayView showOverlayAddedTo:self.view title:title mode:MRProgressOverlayViewModeCheckmark animated:YES];
}
remove success view 1.5s later
- (void)_removeSuccessProgressView {
[self.removeProgressViewTimer invalidate];
[self.suceessProgressView removeFromSuperview];
}

Resources