How do startMonitoringSignificantLocationChanges and startUpdatingLocation effect one-another? - ios

What happens if I call startUpdatingLocation while startMonitoringSignificantLocationChanges is running? Does significantLocationChange monitoring get stopped? If I then stopUpdatingLocation will significantLocationChange monitoring continue or restart?
I can find no documentation covering the interplay between these two ways of monitoring location.

I don't think the accepted answer really answers the question asked. I did some tests and you can use both if you want and they will not cancel each other out.
Why would someone want to use both ? Because startMonitoringSignificantLocationChanges wakes up the app from being suspended or terminated without the need of any background modes. So if you run both you can get accurate foreground location updates and significant location change background location updates.
Of course, you can switch the method, when going into background but a) that wasn't the question b) it adds unneeded logic
Of course, there's a question if running both methods drains more battery, but my bet is that it doesn't.

They are not meant to be used concurrently. It's either or as they both deliver heading and location changes to the same delegate method.
locationManager:didUpdateToLocation:fromLocation
They differ in the frequency and accuracy (and by extension hardware used and power consumption ) of the changes. You as the developer need to decide which is best based on your use case
I have a need to use both approaches at different times. When I switch from one to the other I set a flag that I can reference in my delegate so that I know the type of update.

Standard location service and significant location change service can be used together. Quote from the API Reference:
If both location services are enabled simultaneously, they deliver
events using the same set of delegate methods.
A good reason to use both is that the standard service gives better accuracy, while the significant location change service works even when your app is suspended.

Related

Alternatives to CoreLocation's requestLocation method

I have an IOS app where I require the user's current location in order to make an HTTP request to get data about nearby locations. Since I just need the user's location once, I am using the CoreLocation requestLocation method. This issue with this is that it takes roughly 10 seconds (which is stated in the documentation). I realize that there will always be a delay which I am prepared for, but the delay on requestLocation is just too long and ruins the user experience.
I was wondering if anyone has thought of a way to get the users location (just once) in a more timely way.
One solution I thought of was perhaps calling the method within the AppDelegate, as the app starts, and then passing the data to the ViewControllers via some shared object. The issue I foresee here is that AppDelegate does complete it's application:didFinishLaunchingWithOptions: function very quickly so I don't think it'll improve my problem
Another solution I thought of could be to use the startUpdatingLocation method, and then use stopUpdatingLocation after receiving the first location. My issue with this is that startUpdatingLocation may also take a few seconds to start up (documentation), so again this may not improve my problem.
The location I get for the user does not need to be super accurate so I am willing to compromise on precision for performance.

Switching between significant-location-change monitoring and location-updates monitoring based on application state

We use significant-location-change monitoring to know about our user's whereabouts when the app is not running. This data is based on cellular towers signals and therefore is not very accurate. We would like to use more accurate data whenever it is possible, that is, when the app is active or running in the background.
The question is, should I use "startMonitoringSignificantLocationChanges" and "startUpdatingLocation" at the same time, or, should I switch between those two methods? And if the second option is better, what app delegate events should I use in order to perform the necessary switch?
Unless you want to support a feature that needs continuous high precision location stream, its best to avoid using the high accuracy GPS data via startUpdatingLocation all the time.
I understand from your question that you intend to use more accurate location only at certain points of interest, when your app is woken up. In that case, the second approach of switching-on the more accurate location data only when needed, would be a better idea.
locationManager(_:didUpdateLocations:) in your CLLocationManager delegate would be a good point to start this in your case. Remember that significant location change monitoring API wakes up the system at least once every 15 minutes, even if there are no location changes, until it is explicitly stopped. So one must use it with care.
Instrumenting accurate location tracking while making sure that you don't eat up all of the phone battery is a non-trivial problem to solve. You may want to give third party SDKs like Hypertrack, which specialise in this, a try.

App consuming too much battery

After building the iOS app I wanted, I realized it's consuming way too much battery due to location services.
Background: My app makes a call to the server over network every time a user moves 10 meters (30 ft). This triggers the didUpdateLocation function. When that function is triggered I use NSURLSession to send the users coordinates to the server, that's really about it.
Now the issue lies in that I can't power down location services hardware by calling locationManager.stopUpdatingLocation() after the first update because I won't get any subsequent updates when the user decides to move again. In addition, location services stays active while the app is in the background to monitor movement, also causing a drag on battery life. I have read almost everything about this issue when it comes to documentation and other questions on here.
A lot of other questions suggest using an NSTimer and calling the startUpdatingLocation() after an interval of time has passed by and I have received the first location update and called stopUpdatingLocation in my didUpdateLocation function. So I tried the following:
let timerAction = NSTimer(timeInterval: 6.0, target: self, selector: #selector(MapViewController().startLocationServices), userInfo: nil, repeats: true)
timerAction.fire()
func startLocationServices() {
self.locationManager.startUpdatingLocation()
}
This hasn't worked for some reason or another. But my question really focuses around how I can save battery and make my app really energy efficient when I must monitor a user's movements in the foreground and background with the distanceFilter = 10.0?
Any suggestion maybe around what you have done or what you would recommend would be tremendously sought and appreciated.
Thank you!
Edit
#wain suggested using allowDeferredLocationUpdatesUntilTraveled:timeout:,
Start the delivery of location updates before calling this method. The most common place to call this method is in your delegate’s locationManager:didUpdateLocations: method. After processing any new locations, call this method if you want to defer future updates until the distance or time criteria are met. If new events arrive and your app is in the background, the events are cached and their delivery is deferred appropriately.
You have 2 options:
Use allowDeferredLocationUpdatesUntilTraveled:timeout:
Use significant location change
Try the first, if it isn't available on the device you must sacrifice your 10m goal
I ended up remedying this problem by using geofencing. I create a CLCircularRegion and call startMonitoringForRegion(_:). Every time the user leaves the region (10 meters), I make a request to the server to see where he's at now and update the region. This use little to no battery and is exactly what I'm looking for. Look at the CLLocationManager, CLLocationManagerDelegate and CLCircularRegion classes on how to do this. I hope this will come in handy for someone.

Switch btw. Location Manager & Region Monitoring

for an app that is part of a scientific study I have to implement location tracking (the users who take part in the study know this and are willing to supply this data). The two premises for this app are:
track the user's location with the highest accuracy possible while he/she is on the move
use as little power as possible so that users don't feel the need to shut down the app (turn off location services for it), while they aren't using it
I know these two requirements normally exclude each other :) So the general question is "What would be the best strategy to meet in the middle here?"
My thoughts were to monitor as usual with the highest accuracy possible while location changes keep coming in. If we detect that the delta between theses location updates become almost 0 over a certain period of time, we would assume that the user is not "on the move" anymore and would switch to region monitoring (with a radius of e.g. 40m). Once the user exits that region we'd switch back to regular location monitoring.
So two questions:
Can you tell me if the proposed approach will work for an app that is running in the background?
Have you maybe implemented something similar and know if it really saves a lot of battery power?
Regards,
Sebastian
My thoughts were to monitor as usual with the highest accuracy possible while location changes keep coming in. If we detect that the delta between theses location updates become almost 0 over a certain period of time, we would assume that the user is not "on the move" anymore and would switch to region monitoring (with a radius of e.g. 40m). Once the user exits that region we'd switch back to regular location monitoring.
Using region monitoring to re-engage the location monitoring has a few draw backs, that I have found:
If you set up a region for the user's current location, then wait for -didExitRegion to fire, you're reliant upon the system's default radius cushion, (probably 200m) and some time (probably 20 sec) after they cross out of their boundary before you'll get the message. If accuracy is your main goal, you're likely to loose a lot of data points in between when region monitoring started and when you cross out of the region. Is that acceptable for your needs?
So, to answer your questions:
Can you tell me if the proposed approach will work for an app that is running in the background?
You should not have any trouble running this type of thing in the background. Both location monitoring and region monitoring work when an app is backgrounded, provided you've set it up to do so. Also, to ensure Region Monitoring works on iOS 7 you must have Background App Refresh turned on for your app. That tripped me up.
Have you maybe implemented something similar and know if it really saves a lot of battery power?
In our experience the battery savings were not noticeable. Region Monitoring can be a battery drain that's just as significant as the high accuracy location updates because it uses all kinds of hardware to do it's thing. So pick your poison. Apple's recommendation for saving battery is and always has been to use the significant change location service. It gives you good location data just not as often.

Best way to monitor for a large (50000+) number of regions

I want to create an app which does a specific action when the user enters a certain area.
Since the regions I want to monitor reside server-side (approx. 50.000 locations) and the number of regions is far too large to be registered for monitoring all at once, I want to start monitoring for regions which are close to the current location of the user.
To accomplish this I am thinking about using startMonitoringSignificantLocationChanges
to monitor whether the user has changed location and then use locationManager:didUpdateToLocation:fromLocation:
to register new regions to monitor and unregister regions which are now too far away.
My questions:
Am I allowed do a call to a
web-service in
didUpdateToLocation while the app is
in the background?
Is this the best way to implement this kind of functionality or do you
know of a better way?
Thanks.
What you want is a space-filling-curve for example a z-curve of a hilbert-curve. It reduce the 2D problem to a 1D problem but it's most likely not answering your question.

Resources