locationManager background battery life - ios

I have a question about saving battery when using locationManager. I was looking here:
https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/LocationBestPractices.html
And here:
http://tumblr.twicetwice.net/post/47249353501/cllocationmanager-battery-saving-tips-and-best
And in many stackoverflow postings, but I can't use the most of these tips like startMonitoringSignificantLocationChanges(), because I need high accuracy updates very often, also in the background. Moreover I know that I can't use a timer in the background to get the location for example every 10 seconds. Now I want to stop getting location updates if I don't move for a specific time. And when I move again, I want to get updates again. I can't use
pausesLocationUpdatesAutomatically = true, because I don't want the user to put the app back into the foreground to update the location. Is there any other way to extend battery life when the app is in the background? I also searched for examples with CoreMotion, because I had the idea to turn off the GPS if I don’t move for a specific time and turn it on if the accelerometer detects a few steps. But I found out that this also doesn’t work in the background, or does anyone know a way to get this working? Are there maybe much better solutions for stop updating location when I don’t move and start updating location when I move while the app is in backgound? I would be thankful for any suggestions what I could do.
Btw: I’m pretty new in Swift so maybe there are very easy solutions that I don’t know and that I couldn't find.

Now I want to stop getting location updates if I don't move for a specific time. And when I move again, I want to get updates again
You might be describing Visit monitoring. — But in general, asking for high accuracy locations continuously is very battery-expensive; that is why you're not supposed to do it unless the device is hooked to a source of power.

Related

Waiting with method execution until a condition is met in Swift

I have a MKMapView with some annotations added by code representing users sharing their location. I get updates about location changes via websockets and update the corresponding MKAnnotation.coordinate that represent the annotations in MKMapView.
This mostly works fine, I see the users moving on the map. The problem is that when a MKAnnotation.cooridnate is updated while the user pans or zooms the map then MKMapView crashes saying that a hash table was update while being evaluated. It is basically this problem: MKMapView crashing if zooming while adding annotations
Update: Crashes only occur when clustering is enabled, no need to even pan or zoom, just waiting a bit is usually enough.
The recommended solution is not doing anything (like updating MKAnnotation.cooridnate in my case) with MKMapView between regionWillChangeAnimated and regionDidChangeAnimated and I am tryintg to implement this.
The problem is that my data is being received via websockets so I cannot just "stop" listening for the new data between those 2 delegate methods. Theoretically I can but that would mean losing some data which is not a solution.
My idea was that I need some kind of queue that I will use to add my updates to MKAnnotation.cooridnate and will get paused in regionWillChangeAnimated and resumed in regionDidChangeAnimated.
I tried using DispatchQueue in the way described but it locks after a while. I am not sure if it is because of the high amount of operations being added to it or the calls to suspend and resume. If it does not lock it just crashes the app after a while.
My question is what mechanism will work here?
As stated in the question title, I basically need a way to make some methods wait for a condition, say toggling a flag between regionWillChangeAnimated and regionDidChangeAnimated that is reliable and can take the load.
If you want to not perform tasks while a certain condition is met, use a DispatchQueue and just suspend or resume it. And if this is for tasks that should be performed on the main queue, make the main queue the target for this queue that will be suspended and resumed:
let annotationChangeQueue = DispatchQueue(label: "...", target: .main)
But this begs the question: Under what condition should one should suspend and resume this queue? It would be reasonable to assume (as that other question you reference does) that one could suspend in regionWillChangeAnimated and resume in regionDidChangeAnimated. Alas, this appears to be insufficient. You’ll find that even if you make sure to not do any annotation changes until after regionDidChangeAnimated, it can still crash. And MKMapView doesn’t appear to expose any methods/properties that we can observe to avoid this.
I don’t think there is a proper solution to this problem given that Apple isn’t exposing any property that we could possibly detect when it’s safe to mutate our annotations.
FWIW, I am only able to manifest this issue if I turn on clustering. Also, while the focus of this question was on panning/zooming, I found I was able to reproduce the crash without any panning/zooming. Just was just updating annotations (that participate in clustering) and not touching my device at all, and it eventually crashed with this error. So while it’s easier to manifest with panning/zooming, I think the problem is more fundamental, namely how the map view handles updates to annotations (presumably, only those that may be clustered).

Region monitoring when device is off

I have a client requirement to monitor a region (say MyHome). To alert the user when he leaves MyHome and reaches back to the location. I can handle it pretty easily using the region crossing delegate methods:
locationManager:didEnterRegion:
locationManager:didExitRegion:
My question is, what will be the scenario if my device is off when I am at MyHome location. I leave the location MyHome, move to a different place and switch on my mobile. Will I get the locationManager:didExitRegion: delegate method fired when I launch the app back and thus will be able to notify that I am away from the region. OR will I have to do anything else to get this possible?
First of all monitoring region is not made for such small area to monitor. You may not get actual results. Now, the answer of your question, yes. It is possible. When you will start your device, you will have delegates method to get hit.

GCD in different classes

I have an app where on start it checks the user's position and then get the weather for that spot. Mainly wind direction and speed.
It does the normal check to see it it has Intenet connection, but I found that if there is connection, but very slow the app freezes on launch screen (doing the check on startup).
I have a class that does this, which is called at startup after which a home screen is loaded.looking around, GCD seems the right way to go, but can I get the answer to be displayed in a label in the home screen when it is finished with getting the data? Main tread would have left, or rather bypassed that class and have arrived at the main screen.
Would I need to maybe use something like Notification Centre to help the label updating and re-load?
Thanks for any thoughts or code snippets.
Jorgen
PS. I am trying to keep the app iOS 5.1 to keep old iPads happy.
GCD seems the right way to go, but can I get the answer to be displayed in a label in the home screen when it is finished with getting the data? Main tread would have left, or rather bypassed that class and have arrived at the main screen. Would I need to maybe use something like Notification Centre to help the label updating and re-load?
Yes, I think you're on a very good track here. Let's keep the two issues separate, though:
After doing your background work, still in GCD, you're going to come back onto the main thread because you now want to update the interface. That's easy and straightforward.
If you have a communication problem, a notification can be an excellent solution. You can broadcast the need to update that label, and if the correct view controller exists and is listening, it will get that information.
Having said that, though, you should think about your architecture, since there may be a better way than a notification. Once you are back on the main thread, why are you not in a place where you have a way to know whether the correct view controller exist and to talk to it directly. I'm not saying the notification is bad/wrong! I've used this solution myself, and a notification is quite a standard way to come back from, say, an NSOperation. I'm just saying, give it a little thought.

Monitoring Significant Location Changes, App closed GPS signal (Arrow)

First of all I hope don't repeat any topic, I have spent a lot of time reading on internet about this before ask.
I'm developing an app for iOS => 5 and I need get the user location, but I don't need always a great accurate position, so when the app goes to background I change the normal location mode to Significant Location Changes and when the app come to foreground I stop the significant location change mode and get back the normal location mode, that's all goes fine,
my problem is when the app goes to background mode or even the user KILL the app the GPS signal (the purple arrow) still appear ALWAYS, even after restart the device, the only way to make disappear it is un-installing the or disabling the significant location changes when the app goes to background, but I need this mode working when the user goes to background mode, maybe not when the app is killed.
I don't know how to stop the service when the user kill the app... because event "applicationWillTerminate" is not called if you have multitask ON.
My main reason because I don't want the purple arrow appear always, even the app is killed is because I don't want the user think the app is drying the battery... so the user won't want the app installed.
First question: Is normal that the purple arrow appear always, even the app is killed if the Significant location change is enabled for the app?
Second question: Is any way to change this, to stop the service at least when the app is killed to hide the purple arrow?
Thank you all.
Sorry for my english if something is wrong.
After few days researching to be sure about this service, seems like there is NO way to use significant locations change in the background without the arrow in the top bar. I have been testing with different apps and reading through internet and nothing to solve this.
The only ""way to solve"" this is disable multitask mode in the app and disable the significant locations change in the event "applicationWillTerminate" but don't make sense... I'm losing the background location always not only when the app is killed... so is not useful.
It's bad... is a really good service to get locations saving battery but as user and developer I don't want an app that make appear this icon ALWAYS even after the app is killed, as developer I don't want that people uninstall the app for this reason and as normal user I don't know what mean this icon if is normal GPS or Significant locations change and what mean this... if my battery is being drain or not.
The other option to get locations in background task but has a big impact over the battery....
I hope apple fix this in future versions... adding at least a new arrow or showing only when a new location arrive instad of always or allowing to stooped when the app is killed.
All this has been researched over iOS - 6.1
Thanks to all.
When you use the significant location change service, the OS keeps your app running. If the app is in the background and is killed, the OS restarts it, so the purple arrow will always show. When a new location is detected, the app is restarted. From the docs:
If you leave this service running and your app is subsequently suspended or terminated, the service automatically wakes up your app when new location data arrives. At wake-up time, your app is put into the background and given a small amount of time to process the location data. ... To stop the significant change location service, call the stopMonitoringSignificantLocationChanges method.
Hmmm, interesting. I've just seen that problem with another app - seeing the arrow still active made me want to disable location updates for that app so the problem is real. Best thing I can think of is to have some kind of timer to disable the location monitoring after a certain amount of time if that is appropriate for your app.

Record all touches with timestamp, export touch data to file

I am working on a research project that involves user interaction with an iPod. The application runs for approximately 10 hours, and I need to record the following information:
1) How many times was the screen touched?
2) For each touch, where was it touched? (Inside the button vs.outside)
3) What time was it touched? This would preferably be the time of day, but I can do back-calculations if this is not possible.
This information needs to be saved, and exported to a file that can be manipulated in Matlab, Igor, Excel,etc.
The application itself is very simple. A button in the middle of the screen flashes while playing a sound. When a touch event occurs inside the button, the flashing and sound stop for 30 seconds.
My questions is similar to this one from 2010 How to record all of the user's touches in iPhone app. The asker, however, did not provide the details for how he accomplished this, and I'm afraid I need a little more guidance than is given.
I'd be grateful for some advice, or if you could point me to the appropriate resources. I would especially appreciate it if you could also let me know the general area where the code should go. I'm still getting the hang of objective-C.

Resources