Invoke gets current coordinates every few seconds without NSTimer

I know how to do this with NSTimer, but I won’t get the current iPhone coordinates without a timer for every few seconds. I cannot use the timer because I get the coordinates when the application is in the background.
I tried something, but it causes every second not every 10 seconds, as I do not want.
What am I doing wrong here?

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { CLLocation *loc = [locations objectAtIndex:0]; NSDate* eventDate = loc.timestamp; NSTimeInterval howRecent = [eventDate timeIntervalSinceNow]; if (howRecent < 10) { CLLocation* location = [locations lastObject]; double lat = location.coordinate.latitude; double lng = location.coordinate.longitude; NSLog(@"lat:%f lng:%f", lat, lng); 

First try doing a background job every 10 seconds, but don't know where to set the time if I do something here:

 - (void)applicationDidEnterBackground:(UIApplication *)application { backgroundTask = [application beginBackgroundTaskWithExpirationHandler: ^{ dispatch_async(dispatch_get_main_queue(), ^{ if (backgroundTask != UIBackgroundTaskInvalid) { [application endBackgroundTask:backgroundTask]; backgroundTask = UIBackgroundTaskInvalid; } }); }]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ _pendingLocationsTimer = [NSTimer timerWithTimeInterval:_pendingLocationsTimerDuration target:self selector:@selector(_acceptBestAvailableLocation:) userInfo:nil repeats:NO]; NSRunLoop *loop = [NSRunLoop currentRunLoop]; [loop addTimer:_pendingLocationsTimer forMode:NSRunLoopCommonModes]; [loop run]; dispatch_async(dispatch_get_main_queue(), ^{ if (backgroundTask != UIBackgroundTaskInvalid) { // if you don't call endBackgroundTask, the OS will exit your app. [application endBackgroundTask:backgroundTask]; backgroundTask = UIBackgroundTaskInvalid; } }); }); } 
+2
source share
2 answers

I had problems with timers in the background. There is no guarantee that you will have an active cycle of the cycle, so the timer will not work until you return to the forefront. I have done this:

  NSRunLoop *loop = [NSRunLoop currentRunLoop]; [loop addTimer:myTimer forMode:NSRunLoopCommonModes]; [loop run]; 

I am doing this on a background thread inside the start and end calls of BackgroundIdentifierTask. I'm not quite sure that everything is all right with me, in fact I looked at your question to find out if the answer can help me confirm or correct my understanding of the requirements.

You must also have a background mode for the location services included in your info.pList file by default if you want to constantly monitor your location. You do not need this if you just use significantLocationUpdates or geofence.

My timer works and fires as intended in this way. Prior to that, he had not worked reliably.

Also, you might be best off without a timer. Using your code above, just change the properties of your location manager. The desired accuracy and distance filter are properties that reduce the frequency the dispatcher sends a new location notification.

See an example of my own location handler. I just wrote on github for anyone interested:

http://github.com/dsdavids/TTLocationHandler

I do not think the timer is the key. If you drop the TTLocationHandler class in your project, take a look at how the LMViewController class responds to a handler.

 NSNotificationCenter *defaultNotificatoinCenter = [NSNotificationCenter defaultCenter]; [defaultNotificatoinCenter addObserver:self selector:@selector(handleLocationUpdate) name:LocationHandlerDidUpdateLocation object:nil]; 

sets the controller as an observer. Whenever the handler determines a new or more accurate location, handleLocationUpdate is called.

The locationManager, when startUpdating is called, will send new locations, many per second, first of all, and when moving, until the device becomes stationary and accuracy is reached. TTLocationHandler filters these events and only sends a notification as needed based on the configuration.

Notice that in - (id) init, _recencyThreshold is set to 60. Thus, we save or display the output every 60 seconds. If you want to reduce the interval, change this.

Be that as it may, the TTLocationHandler will always switch to significant changes in location in the background if the device is not plugged in. You will not get such a small interval between updates if it is charged on battery, but you will get updates.

I added a property to configure for continuous background updating without charging.

TTLocationHandler example

I added another class to the repository to show how I will achieve your goals using my handler. I added the LMPinTracker class, where you can add your code to store and load locations.

Take a look at LMAppDelegate.m

  self.pinTracker.uploadInterval = 30.00; 

change this to any length of time between uploads to the server.

  self.sharedLocationHandler.recencyThreshold = 5.0; 

Change the value of 5.0 to the minimum time between saved locations. This will be inaccurate, it will vary depending on the speed and signal strength, but basically, after an interval of x seconds, it will consider the stored location obsolete and try to get a different exact location.

Now look at the LMPinTracker.m file
Put your data storage code right after these two lines:

  // Store the location into your sqlite database here NSLog(@"Received location info: %@ \n Ready for store to database",lastKnowLocationInfo); 

Put your web upload code right here after this comment:

  // Do your upload to web operations here 

Comments

This should do what you are looking for while maintaining battery and background charge.

Basically, when a user travels, updates will be continuous at approximately the interval you set.
When the user is in a stationary state, there will be no updates or significant actions.
When there is no new action, you will not upload it to the Internet.
Registration and updating resume when the user starts moving again.

If I were you, hoping to improve it further, I would think about creating a region and time for verification. If the user remains motionless for a certain period of time, switch only to significant values ​​of LocationUpdates. Then you will turn off location services, but they will come back when the user is started again.

+2
source

I think you can do this in the background using a timer:

 [NSTimer scheduledTimerWithTimeInterval:kAlertInterval target:self selector:@selector(checkLoc:) userInfo:nil repeats:YES]; 

And in your method:

 - (void)checkLoc:(NSTimer *)timer { //...get your location and... if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) { //Do your background stuff } } 

This code works for me in some applications. Please tell me if this works for you.

0
source

Source: https://habr.com/ru/post/1438366/


All Articles