I have a GLKViewController subclass implementation, with an ADBannerView as a subview. Ads load and render just fine. The OpenGL application also works fine. When you click on an Ad, the popup appears. The GLKViewController has the default pause-on-resign behavior enabled.
If you set a breakpoint on GLKViewController's setPaused, you will notice that setPaused:NO gets called if you switch away from your app (double-tap home and pick another app) while the ad popup is visible. The behavior only occurs when an ADBannerView popup is visible, not if you switch away from the app otherwise.
I am able to reproduce the above behavior with even the default OpenGL template app generated by Xcode 7 in iOS 9.1.
1) Is this normal?
2) For me this causes consistent reproducible crashes because after setPaused:NO is called, the GLKViewController is redrawn, which causes OpenGL operations to occur while the app is in the background. The app is (correctly) killed at this point.
My current workaround is to discard calls to setPaused:NO as follows when the application is not active. This appears to work fine but why this is happening at all is confusing me.
- (void)setPaused:(BOOL)paused
{
long appState = (long)[UIApplication sharedApplication].applicationState;
if (!paused && (appState != 0)) {
NSLog(#"setPaused - REJECTING Unpause; %ld", appState);
return;
}
[super setPaused:paused];
}
Related
My app is crashing when you return to it after switching away from it using the 4-finger task-switch gesture on an iPad.
When the user does the 4-finger gesture to switch away from my app, I see applicationWillResignActive: then applicationDidEnterBackground: in my app delegate, then (assuming we're currently in portrait orientation) my top-level view controller gets viewWillTransitionToSize:withTransitionCoordinator: with a size that indicates landscape layout (even though the device has not rotated). This of course results in a lot of resizing and rearranging of views for the new orientation. Immediately after that I get viewWillTransitionToSize:withTransitionCoordinator: with a size that indicates portrait (the original orientation of the device). And again, I go through all my layout again for the new (actually, original) orientation.
What I'm finding is that if I wait for all of this to complete, I can switch in and out of my app all day. If, on the other hand, I switch back to my app while this needless work is going on, I get a crash deep in some iOS transition code.
At this point I'm trying to understand why I get these stray rotation events. If I can avoid getting those, I can avoid getting into whatever situation is causing the crash. They don't seem necessary.
I can't think of a reason why it would be useful or correct to get viewWillTransitionToSize in the background, so just bounce out if you are in the background:
if UIApplication.shared.applicationState == .background {
return
}
Still, this feels like a bug, and in my opinion you should report it to Apple.
It turns out there isn't a way to prevent the rotation events from being reported to the app. I suspect that's an iOS bug. However, ignoring viewWillTransitionToSize:withTransitionCoordinator: when the application state is UIApplicationStateBackground and doing the same in the view's layoutSubviews (if present) allowed me to work around the problem.
I noticed some bizarre behavior in my iPad app: when the app transitions to the background, my active view controller receives viewWillAppear/viewDidAppear messages.
From my investigation, it seems this is happening because when my app moves to the background, my UISplitViewController for some reason first transitions its display mode to .PrimaryHidden and then immediately back to what it was before (.AllVisible).
Is this expected behavior? If so, why does UISplitViewController need to change its display mode (twice) when the app suspends, and is there a way to prevent it from doing so?
Edit: I just verified this behavior with a simple test app, but I'm no closer to understanding why it happens or how to prevent it.
I have a camera app that is running fine on iOS 7. In the viewDidAppear call of my MainViewControllerI am first checking if the application state in not inactive and the application is not in background.
The code sample is given below.
-(void) viewDidAppear
{
if ((UIApplicationStateBackground != [UIApplication sharedApplication].applicationState)
&& (UIApplicationStateInactive != [UIApplication sharedApplication].applicationState))
{
// check if the camera is running
// perform the animation of opening shutter.
}
}
My problem is that on iOS 8 beta 2 [UIApplication sharedApplication].applicationState returns UIApplicationStateInactive hence the check fails. But on iOS 7 [UIApplication sharedApplication].applicationState returns UIApplicationStateActiveand works without any problem.
Has anyone else faced the same issue?
EDIT
A simple experiment of putting breakpoints in viewDidAppear and appDidBecomeActive in xcode 6 reveals that viewdidAppear gets called first. I suppose its a bug in iOS 8
Your view could not possibly appear unless the app was active, or at least becoming active. Views don't do things like appear when the app is inactive or in the background. So I would just delete that condition entirely if I were you. It was never serving any useful function.
(By the way, if you're encountering this situation on launch, what you're experiencing sounds like an issue that I've reported to Apple in another form: in iOS 8, the application doesn't switch to active (so that application:didBecomeActive: fires) until very late, well after the whole interface is up and running. This has caused me to have to rewrite quite a lot of my code. For example, if use my root view controller's viewDidAppear: to register for the applicationDidBecomeActive notification, I then receive that notification shortly afterwards — which is nutty.)
My app checks the GPS while my app is not the active app and I use AVAudioplayer too in background.
It works fine and stays in the background doing its thing, but ios7 displays this red top banner with my app name flashing on it when it is not the active app.
How can I disable this banner, it is annoying to use other apps that are squished down 1 line?
I know this can be done as I have other GPS based background apps that don't display this flashing banner.
EDIT - So we found the answer quickly but the solution evades me:
If I stop OpenEars pocketsphinxController from listening with a button that calls this method while the program is active, the banner disappears when the app loses focus:
-(void) mystopListening{
NSLog(#"Tried to stop listening");
[pocketsphinxController stopListening];
}
BUT if I call the same method from my app delegate with (I had to import my view controller.h file in my app delegate.h and add -(void) nystopListening; in my view controller.h to make the below execute properly):
- (void)applicationWillResignActive:(UIApplication *)application{
myViewController * vc = [[myViewController alloc]init];
[vc mystopListening];
}
The banner persists! It is a little like ios7 has decided I am a recording culprit before I even have a chance to turn it off. OR, am I even turning it off?
How do I do this effectively and in what event?
EDIT - So it turns out I am not really turning pocketsphinxController off when 'mystopListening' is called from the app delegate. I know this because it DOES log the 'Tried to stop listening' when called from app delegate but the pocketsphinxController does not respond with its 'pocketsphinxDidStopListening' method. PocketsphinxController does call its 'pocketsphinxDidStopListening' method when I call 'mystopListening' from a button while the app is active.
Why won't the pocketsphinxController respond when called from from the app delegate, I must be doing it wrong?
Thanks,Carmen
Turns out I was not really calling the original pockectsphinxcontroller instance from my app delegate.
As a workaround to the problem I did this:
My app always has a timer running, so in my app delegate where I get notice of when app goes to inactive and comes back active, I just set global flags so my timer can know app active status. Then my timer just uses pockecsphinxcontroller methods to stop and start listening and voila, the banner is no more while app not active.
I have some odd behaviour in the iOS Simulator with state restoration. I've only recently realized it is only happening in the emulator. I'm wondering if there is something I am doing wrong. But I would also like to share my experience.
I created a single screen project in Xcode 5.0.2. In my application delegate I have only added two methods:
- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder
{
NSLog(#"I am restore.");
return YES;
} // */
- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder
{
NSLog(#"I am save.");
return YES;
} // */
There are no other changes.
When debugging on an actual iPhone, I get both the log messages; "I am restore" on start up, and "I am save" when I press the home button to stop the app. If I comment out either one or both, I do not get any log messages. It seems that you need both methods for either to work. They don't even get called without the presence of the other.
When debugging in the iOS Simulator, (I don't know how to tell what version of the OS I'm using in the Simulator) I never get either of the log messages. If both methods are present, and only if both are present, I get "Warning: Unable to create restoration in progress marker file" showing up in my log, but I still don't get the log messages I made. So, the mere presence of both will cause a warning, but no force on Earth will allow them to be called. In the simulator. I tried adding a restoration id in the storyboard, but it didn't change anything.
I realize that Apple recommends running on an actual device and they don't guarantee similar behaviour on the simulator. But is there some setting I need to put somewhere to get state restoration working in the simulator? At one point I had it working, and I assumed that my storyboard changes had disrupted it. But with such a minimal app, I'm wondering if there is something more fundamental.
This is not a bug. These methods are called in preparation of state serialization for your app. State serialization never happens in the simulator because the app will not be terminated.
Ultimately, this is one of many differences between the simulator and actual devices. Always test on a device to ensure actual functionality.
Edit: State serialization can happen in the simulator by press the simulated 'home' key. ⌘⇧H
Often, the simulator start acting funny and the solution to most problem there is just to reset it.
In the simulator, click on the 'iOS Simulator menu' > 'Rest Content And Settings...'
I do this I think at least once a day, when the keyboard just stops responding or I get funny messages out of the blue.