iOS: Monitoring Battery Level uses more battery? Should auto-save? - iphone

I have a GPS app that already uses a fair amount of battery. Because of the nature of the app, I don't want the user to loose all of their data if their battery dies without them knowing it. So, I figured I would monitor the battery and then save and stop the GPS data if the battery is very low. I would use:
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(batteryStateDidChange:)
name:UIDeviceBatteryStateDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(batteryLevelDidChange:)
name:UIDeviceBatteryLevelDidChangeNotification
object:nil];
So, a few questions:
Would monitoring the battery cause even MORE battery drain?
Is it a good idea to auto-save (core-data) for the user right before the battery dies?

The device already has to monitor battery notifications in order to display the battery level when the time / carrier / signal strength is visible... I wouldn't expect registering for the notifications would add any additional stress to anything (power consumption). Maybe a few extra cpu cycles from your app for handling the notification. :-)
Auto saving might be a smart idea.
But another idea might be to cease GPS / CoreLocation services for your app once battery gets underneath a certain level (or offer that as a user-settable option).

If the iDevice dies while your application is running or while the device is "sleeping" your UIApplicationDelegate will be sent a applicationWillTerminate: message.
If the application was put in the background then you can handle the saving there as well in your appdelegate's applicationWillEnterBackground
Be careful about Autosaving it can randomly cause CPU usage causing your user interface to be jerky at supposedly "random" intervals.

Related

NSTimer stops in Background while power cable is disconnected

I have created GPS base Application.
In which App logged GPS data every 1 second.
App used the NSTimer to fetch GPS data every second.
This NSTimer is start in background. The NSTimer is start when app received the silent push notification from APNS.
I have seen a problem in iOS 7 that when Phone attached with power cable at that time timer call appropriately but without attached power cable timer stops while App in background.
Any inputs to resolve this issue greatly appreciated.
An NSTimer is not guaranteed to fire if your app is not in foreground. Once you unplug the cable the system puts your app into background to save battery.
Using an NSTimer is not the supported method to get location data. Your CLLocationManager will tell its delegate when there is a new location. No need to poll it.
If you need to track geolocation in background you need to declare location updates as a background mode from the capabilities tab in Xcode 5 target settings. Otherwise your location manager will stop delivering location updates once your app is not in foreground.
There are only few use cases that you can implement for foreground. If you don't want your application to be refused within review please don't use any hacks. Of course, you can use NSTimer in background, but it must be created in thread (runloop) of background task. But this background task lives for the only certain amount of time, so your timer must fire during this period. In other words, your first goal is to create background task, and only then you can use the timer. There are few cases suitable for your purpose (that allow you to create this task): 1.Monitor significant location changes or region 2.Fetch data (iOs 7). So please refer
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(#"BG fetch in action");
//the only 30 sec is allowed to perform all your actions
//during this period you can each second track GPS data
[self performSelector:#selector(finishBackgroundFetch:) withObject:completionHandler afterDelay:27];
[[NSNotificationCenter defaultCenter] postNotificationName:#"StartMyGPSRoutine" object:nil];
}
-(void)finishBackgroundFetch:(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(#"BG fetch completion handler");
[[NSNotificationCenter defaultCenter] postNotificationName:#"ForceStopAnyBackgroundTaskCreatedWithStartMyGPSRoutine" object:nil];
completionHandler(UIBackgroundFetchResultNewData);
}
of your application delegate -- this will be useful in your case as well as monitor significant location changes.
You ought to put anywhere:
if ([[UIApplication sharedApplication] respondsToSelector:#selector(setMinimumBackgroundFetchInterval:)]) {
NSLog(#"Set Force BG interval to %ld", interval);
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:interval];
}
In my case I fetch the GPS data each 5 min so 27sec to complete this task is not so long. Anyway you can play with time intervals with XCode. Please refer Main Menu->Debug->Simulate Background Fetch

Detect low battery warning ios [duplicate]

This question already has answers here:
Detecting the type of iPhone interrupt
(2 answers)
Closed 10 years ago.
I'm making a turnbased game. To prevent users from cheat, the turn will automatically get passed to the opponent if the user close the app in the middle of a turn. This because so the user can't close the app, restart it, and beging the turn from the beginning.
There are two cases that should penalize the player however. If a phone call gets in, or the low battery warning appears. I can detect the phone call coming in and respond, but I don't know what to do with the battery?
Any suggestions would be awesome
Battery monitoring is enabled by setting to YES a property of the UIDevice singleton:
UIDevice *device = [UIDevice currentDevice];
device.batteryMonitoringEnabled = YES;
iPhone OS provides two type of battery monitoring events, one for when the state changes (e.g., charging, unplugged, full charged) and one that updates when the battery’s charge level changes. As was the case with proximity monitoring, you register callbacks to receive notifications:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryChanged:) name:#"UIDeviceBatteryLevelDidChangeNotification" object:device];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryChanged:) name:#"UIDeviceBatteryStateDidChangeNotification" object:device];
ALso refer this link.

Prevent iPhone from locking when connected to charger and app is running

I'm writing an iPhone app. When the app is running and the iPhone is charging, there is no need to lock the iPhone. Is it possible to prevent the locking of the iPhone when the device is charging and my app is running?
You can subscribe to UIDeviceBatteryStateDidChangeNotification notification to get the moment when your iphone begins/stops to charge. Then in case iphone is charging you can set idleTimerDisabled property in UIApplication object to YES to prevent device to go to sleep:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(updateBatteryState:)
name:UIDeviceBatteryStateDidChangeNotification
object:nil];
- (void) updateBatteryState:(NSNotification*)notification{
[UIApplication sharedApplication].idleTimerDisabled =
([UIDevice currentDevice].batteryState == UIDeviceBatteryStateCharging);
}
P.S. If user decides to put device to sleep with sleep/wake button there's no way to prevent him of doing so
This is not possible with current SDK.
EDIT: hmm, haven't got the question correctly from the first read - look on other replies for correct answer; my guess was, you were asking about if it possible to prevent appearance of the sync/charge screen when connecting device via usb or to the wall outlet

Location services don't stop when application is terminated

I'm currently developing an iPhone application which needs location services for various use including AR.
I test everything on simulator and on my iPhone 3GS and everything went well.
I recently tested on iPhone4 and on iPad2 and the location service (the little icon in status bar) keeps displaying even when I manually kill the app!
The only way to disable this icon is to manually stop the location service for my app in the settings.
Does anyone know something about this?
If needed I can post my code.
Thank you in advance
Edit :
When I kill the application, go to location services, switch off my app the location icon disappears. But when I switch it back on, it reappears! Is that normal?
I've found the answer! It came from region monitoring, which I enabled before, but removed all code using it weeks ago.
As I had already tested on the iPad, and even if I deleted and re-installed the app, the system seems to have kept information on region I monitored.
Thus, as described by the documentation, the iOS kept on locating for my App, just as startMonitoringSignificantLocationChanges.
Thanks for you answers, it gave me a better understanding of the location system and how to efficiently use it (in particular thanks to progrmr and Bill Brasky)
Sounds like you're app is going into the background and still using CLLocation. You can stop CLLOcationManager when you receive notification that you're app is resigning active, that's the best way. Then resume when it becomes active. The answer in this question show how to do that here
[EDIT] When your app goes into the background or resigns active for any reason (ie: phone call) you should stop location services at that time. You need to subscribe to the notifications and provide a method to stop and start location services, something like this:
-(void)appDidBecomeActiveNotif:(NSNotification*)notif
{
[locationManager startUpdatingLocation];
}
-(void)appWillResignActiveNotif:(NSNotification*)notif
{
[locationManager stopUpdatingLocation];
}
-(void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appDidBecomeActiveNotif:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appWillResignActiveNotif:) name:UIApplicationWillResignActiveNotification object:nil];
}
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
I ran into this same exact issue when using the region monitoring tools. It didn't matter what I did to disable the regions, the arrow remained. I did finally solve the issue by cleaning up the calls to locationManager. If you are closing your view and don't need the location manager, set it to nil and/or release it. If you are monitoring location in the background, it will stay up there, but if not, make sure you are cleaning up all your location monitoring.
It seems like it is a bug, but as I found out, it is not. Just requires a bit more cleanup.
I have been battling with this problem for a while, and I think I've finally gotten to the bottom of it..
The reason that the location service doesn't stop when you ask it to is not because you haven't stopped it or released it properly. It's actually caused by releasing and re-allocating the CLLocationManager itself, in my experience.
If you have code which releases your CLLocationManager in applicationDidEnterBackground, and then you allocate a brand new one in applicationDidEnterForeground, etc., then you'll probably have this problem.
The solution is this:
Only create your CLLocationManager object once, in applicationDidFinishLaunching.
To start, call startUpdatingLocation, startMonitoringSignificantLocationChanges etc. as normal.
To stop updates, call the appropriate stopUpdatingLocation, stopMonitoringSignificantLocationChanges etc. as normal.
Never, ever release your CLLocationManager or set its' reference to nil (except possibly in applicationWillTerminate, but that probably won't make any difference).
This way, I went from having my app continue to use location services for up to 12 hours after putting my app away in the background, to the location services arrow disappearing within 10 seconds of backgrounding with this new approach.
Note: Tested on iPhone 4S running iOS 5.1.1. To get accurate results on your app's performance in this regard, make sure you go into Settings->Location Services->System Services and turn off the Status Bar Icon switch. That way, the status bar arrow will accurately reflect usage by apps alone.
Presumably this is so users don't need to stare at the bar to notice some mischievous app is using location services. That icon appears when you use any location services and remains for some indeterminate time afterwards.
This is intentional behavior Apple wants users to know which apps are using their locations. It seems this is sensitive data, wouldn't you agree?
This is the solution which fixed this problem for me.
Just stop monitering location changes in
- (void) applicationDidEnterBackground: (UIApplication *)application
{
[locationManager stopMonitoringSignificantLocationChanges];
locationManager.delegate = nil;
}
not in applicationWillEnterForeground: .Still,it takes a few seconds to disappear locating icon.
I don't know why it isn't working in the latter method.
I've run into that problem a while ago and found it useful to apply only one method of applicationDelegate object
- (void)applicationWillEnterForeground:(UIApplication *)application;
If you'll stop your CLLocationManager from receiving updates inside that call, you'll be alright. Of course you'll need to start updating somewhere else, and - (void)applicationDidBecomeActive:(UIApplication *)application; will be a good choice. Also you need to note, that there are two methods of location awareness
the gps based -(void)start/stop_UpdatingLocation;
and the 3g/wi-fi based -(void)start/stop_MonitoringSignificantLocationChanges;

How can I tell my app is about to become inactive/go to background state?

I am assuming I need to implement:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(resignActive:)
name:UIApplicationWillResignActiveNotification
object:nil];
but am not sure if this is the right notification to determine my app is about to leave active state.
Is this a good place to cancel network connections, along with app termination?
There are cases where UIApplicationWillResignActiveNotification is sent but the application does not enter the background, for example if a call is received but the user chooses not to answer it.
Use UIApplicationDidEnterBackgroundNotification to be notified when entering the background. Be aware that this will sometimes be sent after UIApplicationWillEnterForegroundNotification if the application is quickly opened again.