I've attempted to prevent my app from doing any OpenGL in the background, but it's still getting killed occasionally out in the field, and I haven't been able to reproduce it yet.
The OpenGL use is for rendering document thumbnails.
Definitively, where should OpenGL be started and stopped?
Apple's docs are seemingly inconsistent. In the OpenGL ES Programming Guide for iOS, we have:
In your app’s applicationWillEnterForeground: method, re-create any objects and restart your animation timer.
And in the App Programming Guide for iOS, we have:
Apps that use OpenGL ES for drawing must not use these methods to prepare their drawing environment. Instead, defer any OpenGL ES drawing calls to the applicationDidBecomeActive: method.
Apparently, applicationWillEnterForeground is called before applicationDidBecomeActive. That wold mean that starting animation in applicationWillEnterForeground would not defer drawing calls to applicationDidBecomeActive.
Currently, I'm doing the following:
Start thumbnail rendering in applicationDidBecomeActive and applicationWillEnterForeground
Stop thumbnail rendering in applicationWillResignActive per documentation.
I'm using an OperationQueue for thumbnail rendering and do the following to stop the queue:
func stopQueue() {
// Ensure all operations are finished so we don't
// call OpenGL while the app is backgrounded.
workerQueue.waitUntilAllOperationsAreFinished()
workerQueue.isSuspended = true
}
Related
I am getting this report from crashlystics and, what does it means and how I can solve this issue to stop crashing my music application
http://prntscr.com/kbl58s
Screenshot of App delegate:
http://prntscr.com/kbm77y
http://prntscr.com/kbm7q4
http://prntscr.com/kbm7xh
http://prntscr.com/kbm83a
//Application background state
http://prntscr.com/kbm8dn
http://prntscr.com/kbm8nf
According to your screenshot of crash infos, the key reason is OpenGL rendering on app background state.
So observe app's state, stop OpenGL rendering while it is going to enter background
and resume OpenGL rendering while it's coming back to foreground.
How to observe this?
the methods in UIApplicationDelegate:
applicationDidEnterBackground: and applicationWillEnterForeground
Two system notifications: UIApplicationDidEnterBackgroundNotification and UIApplicationWillEnterForegroundNotification
Check [UIApplication sharedApplication].applicationState;. Stop openGL unless applicationState is UIApplicationStateActive
I'm using a GPUImage library for developing an iOS camera app.
I found sometimes app crash with GPUImageContext.
I noticed it via Crashlytics Crash report,
and App crash at GPUImageContext.m line 196, below method.
- (void)presentBufferForDisplay;
{
[self.context presentRenderbuffer:GL_RENDERBUFFER];
}
I confirmed below question, but I support below case.
Mysterious app crash with OpenGL
Does anyone suggest the reason of this crash?
I receive crash report, most crash(90%) occur in iPod.
You can't access OpenGL ES at all when your application is running in the background (suspended). GPUImage uses OpenGL ES for everything it does. You have to make sure that all work your application is doing with GPUImage (filtering video, processing an image) is done before your application completes its transition to the background.
You need to listen for the UIApplicationWillResignActiveNotification or fill out the related delegate callbacks for the transition to the background, and in there pause any camera capture (via the -pauseCameraCapture method on your camera input) or wait for any processing to finish (I believe a synchronous dispatch into the GPUImage serial dispatch queue will take care of this).
Related discussion for this can be found on the GitHub issues page here: https://github.com/BradLarson/GPUImage/issues/197 and in several related issues.
Doing some investigation online, I've noticed that gpus_ReturnNotPermittedKillClient gets thrown when OpenGL actions are triggered while an app is backgrounded. I'm currently working on a project that involves a map view and an overlay (using Apple's Breadcrumb sample code). These actions are performed on the main thread, but there's a possibility that the app could get backgrounded as the map view becomes initialized or the view gets pushed onto the screen.
I also use location services to retrieve points through GPS, but I don't update the overlay unless we're in the foreground.
Is it to my understanding that since iOS 6, MKMapView's are now created with OpenGL? If this is the case, then could drawing the overlay also be through OpenGL? This could help explain why I've been getting this error randomly.
I've heard of some ways to cancel all OpenGL actions, such as invoking glFinish() in applicationDidEnterBackground and applicationWillResignActive or using [[CCDirector sharedDirector] pause]. Considering this, what would be the best solution to eliminate any OpenGL drawing with an MKMapView/MKOverlayView?
After trying multiple solutions, I realized that the thing that was causing this crash was an adjustment of the map view's frame that was being fired off a few seconds after the map was allocated. A status bar is dropped down, and the map's frame was animated downward by a few pixels. Because of this, the map (supposedly) had to be re-drawn, causing a crash if this animation was occurring in the background.
I now keep track of the state of the status bar in relation to the app's active status, and only animate if the application state is UIApplicationStateActive. Having done this, I haven't had a crash since.
I have a media player app that is playing music with MPMoviePlayerController. I need to update the UI based on the playback position. The best I can tell, there is no way to actively receive this info from the player with a callback or something, and I basically need to poll for it myself.
So I thought I would use a simple timer, run every second, for that. The code is such:
Somewhere in the setup code:
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(updatePlaybackProgressFromTimer:) userInfo:nil repeats:YES];
And then:
- (void) updatePlaybackProgressFromTimer:(NSTimer *)timer {
if (([UIApplication sharedApplication].applicationState == UIApplicationStateActive) && (player.playbackState == MPMoviePlaybackStatePlaying)) {
CGFloat progress = player.currentPlaybackTime / player.duration;
// do something useful with this info
}
}
The timer is run every second, even when the app is in the background. The method first sees if the app is active and the player is playing, and then does some UI updating.
Is there any battery life implication to running a timer every second in this fashion? Should I be more diligent and try to tear down the timer when entering the background and reactivating it when activating the app? I’m sure there’s some battery life effect, but realistically, how serious is it? Or is there any other recommended ways of doing this kind of thing?
I can't imagine using an NSTimer will significantly impact battery life - unless the work being done when it is triggered impacts battery life. The timer is simply being added to the current run loop:
A timer is not a real-time mechanism; it fires only when one of the
run loop modes to which the timer has been added is running and able
to check if the timer’s firing time has passed.
NSTimer Class Reference
According to the documentation, you should be pausing any timers when your application is about to resign its active status:
In response to this change, your app should do the following in its
applicationWillResignActive: method:
Stop timers and other periodic tasks.
Stop any running metadata queries.
Do not initiate any new tasks.
Pause movie playback (except when playing back over AirPlay).
Enter into a pause state if your app is a game.
Throttle back OpenGL ES frame rates.
Suspend any dispatch queues or operation queues executing non-critical code. (You can continue processing network requests and
other time-sensitive background tasks while inactive.)
When your app is moved back to the active state, its
applicationDidBecomeActive: method should reverse any of the steps
taken in the applicationWillResignActive: method. Thus, upon
reactivation, your app should restart timers, resume dispatch
queues, and throttle up OpenGL ES frame rates again. However, games
should not resume automatically; they should remain paused until the
user chooses to resume them.
iOS App Programming Guide
Cocos2d templates and the usual sample projects initialize cocos openGL ES view and other stuff in the applicationDidFinishLaunching / application:didFinishLaunchingWithOptions: method. In relation to the last method, Apple iOS Programming Guide states that:
"Apps that use OpenGL ES should not use this method to prepare their
drawing environment. Instead, they should defer any OpenGL ES drawing
calls to the applicationDidBecomeActive: method."
So, my question is, is application:didFinishLaunchingWithOptions: really the proper place to initialize cocos2d? or should we be doing that in applicationDidBecomeActive: ?
If you think that applicationDidBecomeActive: is the way to go, what would be the consequences in relation to background execution? i.e. what should we do to avoid a sort of double initialization when the app comes to foreground from being inactive?
Thanks in advance
Good question … so far 99.9% of all cocos2d apps do it the way cocos2d does it and I haven't heard of a single issue.
Since Apple doesn't really explain why this is particularly important for OpenGL ES apps, I would assume the following:
OpenGL ES apps tend to take a relatively long time to initialize their view. In particular when loading lots of assets. This could lead to the App being killed by the system if it takes too long. That means the Cocos2D first scene should load fast, and in particular it shouldn't load all the game's assets unless loading of the first scene is deferred to applicationDidBecomeActive. The latter requires an additional check to make sure there's no other scene already running.
Apps are supposed to perform common tasks in applicationDidBecomeActive. This is generally good advice because some settings can now change while the app is suspended. For example the user might change the device language, or enter Airplane Mode and the app needs to respond to that when it becomes active again. Some changes may affect OpenGL ES apps in particular, like for example reloading all bitmap fonts if the user changed locale from english to japanese.