My game made using cocos2d crashes on iOS5 after resuming from the background when left for a while. I want to know what the standard/best practice is, on handling an app that is sent to the background. Do I terminate it after a certain time? I see some games pull up a loading screen when you resume it after a long time but when you resume it immediately it goes straight to the game. What are they loading when they resume?
Any pointers in the right direction would be much appreciated.
Thanks
AC
You can opt out of background execution by adding UIApplicationExitsOnSuspend to your Info.plist.
Other than that it really is your job to ensure that your app doesn't crash when it resumes execution. You have to understand that your application basically enters a suspended state. That means it should unload all unneeded resources, otherwise the system may terminate your app's process.
In your app delegate you should respond to the applicationDidBecomeActive message and respond accordingly so that your app is able to resume execution without any issues. This can include loading any unloaded assets and checking if system settings (ie. locale, Game Center user, etc.) have changed.
You can also register a didBecomeActive UINotification so that any class in your app gets notified when the app should resume.
Related
I am building a word game and I want to hide the board when application is suspended?
the code looks fine however it givs a strange behaviour!!,
when I suspend the app nothing will happen but when i resume the application then the board will hide!!
local onSystem = function( event )
if event.type == "applicationSuspend" then
print("suspend")
board_group.alpha = 0
end
end
Runtime:addEventListener( "system", onSystem )
Note: you might wonder how do I know how the application looks when suspended?
the answer is: by pressing the home button twice.
example
SpellTower in normal state
https://dzwonsemrish7.cloudfront.net/items/430k0c0b0y0b413d0b42/Image%202012.11.12%208:08:24%20AM.png?v=4822f549
SpellTower after pressing the home button twice
https://dzwonsemrish7.cloudfront.net/items/280a1y0r2U3W321y1B2z/Image%202012.11.12%208:08:31%20AM.png?v=09c37567
you can see how they are hiding the letters, this is exactly what I want to do for my game, the only difference is i am using Corona SDK
When you do board_group.alpha = 0 you only has set a variable, the result will only take effect after a screen update.
But since the application is suspended... it won't update! So, changing any graphics on applicationSuspend don't work.
I believe the reason is because the application is not considered as suspended. In normal objective c programming it means that applicationWillResignActive is called when the user double clicks on the home button. So what you want to do is to add that code for this part.
Here is a flow of events:
http://www.cocoanetics.com/2010/07/understanding-ios-4-backgrounding-and-delegate-messaging/
Corona seems to have these events:
"applicationStart" occurs when the application is launched and all code
in main.lua is executed.
"applicationExit" occurs when the user quits the application.
"applicationSuspend" occurs when the device needs to suspend the application such as during a phone call or if the phone goes to sleep
from inactivity. In the simulator, this corresponds to the simulator
running in the background. During suspension, no events (not even
enterFrame events) are sent to the application while suspended, so if
you have code that depends on time, you should account for the time
lost to an application being suspended.
"applicationResume" occurs when the application resumes after a suspend. On the phone, this occurs if the application was suspended
because of a phone call. On the simulator, this occurs when the simulator was in the background and now is the foreground application.
So my guess is that you have to implement it outside of the corona API.
According to the corona documents you can implement them in the delegate:
You can intercept UIApplicationDelegate events via your implementation
of the CoronaDelegate protocol.
This protocol conforms to the UIApplicationDelegate protocol. Corona's
internal delegate will call your protocol's method if it is
implemented.
Please keep in mind the following:
Methods that Apple has deprecated will be ignored.
In most cases, your class' version will be invoked after Corona's corresponding version of the UIApplicationDelegate method. There is one situation in which your version will be called before.
In situations where the app is about to suspend or go to the background, your method will be called before Corona's version, e.g.
applicationWillResignActive: and applicationDidEnterBackground:.
http://docs.coronalabs.com/native/enterprise/ios/CoronaDelegate.html
But this is just a guess. Hope it helps!
Edit:
I was thinking, something really simple you could do is catch it outside and present a "pause" screen, then just hide it when the application enters foreground.
So if you can't do that (for now), one other option is to save application state when the application is about to terminate, and then set UIApplicationExitsOnSuspend = true in your plist file. This will cause the application to exit instead of suspending, which will avoid any screenshots, effectively "hiding" the board, etc. The downfall is, the app will have to read the session state when it launches again... this is only useful if your application can be designed to actually exit without losing your state, and is quite honestly, a little extreme. That said, it may be the only way to effectively do what you're trying to do.
Other ideas would be to see if you can add a large black layer to the screen, even though the application is suspending; perhaps this will somehow trigger an internal screen update by natively setting setNeedsDisplay. Also, instead of modifying the alpha, you might consider temporarily removing all of your layers and see if that has a similar effect.
My application triggers the iPhone Dialer and goes to background via the App Delegate.
Somewhere in the AppDelegate.m file this is called:
- (void) applicationDidEnterBackground: (UIApplication *) application
{
[self terminate];
}
When I am finished with my external app (Dialer) the application is launched again but most of the GUI parts are unresponsive.
Does it ring a bell? How could I debug this issue? Let me know if you need more info.
To be more helpful. The application is an address book that each entry is dialable and when click the iOS app is called. During the call I want to be able to open my app to browse information
I am assuming that your main issue here is that you do not consider the effects of being suspended. Please see this question: iOS 4 resume from background
Then consider reading up on an apps state cycle, which you can find here
Among the things of importance found in this article are:
To help reduce your app’s memory footprint, the system automatically purges some data allocated on behalf of your app when your app moves to the background.
The system purges the backing store for all Core Animation layers. This effort does not remove your app’s layer objects from memory, nor does it change the current layer properties. It simply prevents the contents of those layers from appearing onscreen, which given that the app is in the background should not happen anyway.
It removes any system references to cached images. (If your app does not have a strong reference to the images, they are subsequently removed from memory.)
It removes strong references to some other system-managed data caches
In other words, the state of your application might not be the one you had when you were put in the background. The entirety of this process is too large to elaborate here, and should instead be researched through the documentation provided by Apple, which I have linked to above.
You get applicationdidEnterBackground when you go into the background, but when that happens, you're trying to quit your app completely? Better than doing that there's a info.plist key that will tell the OS not to enter the background "application does not run in back ground." That will terminate your app much more gracefully.
I have a application that periodically (via an NSTimer) asks for the users location using locationManager:startUpdatingLocation I want the locationManager to run in the background so have entered "UIBackgroundModes = location" in the info.plist file.
My question is I am not seeing the results I expected, am I right in thinking that when I press the home button the application delegate calls "applicationDidEnterBackground" but although locationManager is allowed to continue my NSTimer is getting suspended (and as a consequence its not calling startUpdatingLocation to periodically query the devices position). Any ideas / solutions would be much appreciated ...
Gary.
All NSTimers are invalidated when entering the background. You need check via the CLLocationManager for any changes.
Just keep the startUpdateLocation running, you delegate will receive any major changes of the location.
When running in the background, you will only receive location changes based on cell towers.
If you read the documentation for -applicationDidEnterBackground: you'll find that yes, your timers are invalidated. Furthermore, the iOS Application Programming Guide tells you exactly how to track location from the background.
My App needs a Internet Connection which is checkt in the ViewDidLoad if there is no Internet connection I want to terminate the app when the Home Button is clickt so that the app start in its initial state next time but only in this case.
If there is a Internet connection from the start the homeButton should bring the app just to the background.
Apple does strongly discourages quitting from application programmatically.
I think you can handle your case without quitting application - when application goes to background(in applicationDidEnterBackground method of application delegate) save some flag indicating that you want to reinit it on resume, then when application comes back to foreground (applicationWillEnterForeground method in delegate) apply your initialization logic in case flag is set.
Programatically terminate an App is a behaviour that will be rejected to be published in the AppStore, as it seems that the application crashed.
If you don't mind that your application will never see the light at the AppStore, you can simply use exit(0).
When your app does not find an internet connection, switch to a view that exactly imitates your Default start-up image, then force that view to stay visible the usual amount of start-up time after any call to making your app active. You can also kill and recreate fresh all your other MVC objects during this time.
That way, no one will know that your app wasn't freshly started when brought back from the background.
When my iPhone app resigns active status, the sharedAccelerometer singleton instance of UIAccelerometer stops sending accelerometer:didAccelerate: messages to my delegate.
Is it at all possible to continue receiving those messages, similarly to how the CLLocationManagerDelegate continues to receive updates when the app is inactive?
I would prefer not to have to disable the idleTimer altogether if it can be helped.
No, not in the most recent available form of the iPhone SDK at least.
I would say that it is possible since this app is on the AppStore:
However, since you move differently in
bed during the different phases, the
Sleep Cycle alarm clock is able to use
the accelerometer in your iPhone to
monitor your movement and determine
which sleep phase you are in.
I can't believe it has to run all night with the screen turned on. EDIT: looks like it has to! :P
So they haven't got around that issue either. More chances that you can't achieve it then...
Have you read the documentation of the UIAccelerometer, does it mention anything there? If it just stops sending acceleration events there is not much you can do.
I would however try to set the accelerometer delegate again to my class when my app has lost focus (when the phone got locked). You can get that notification (lost focus notification) from the UIApplication. Try that just in case the accelerometer's delegate gets set to nil when the app loses focus.