While using my app, the screen sometimes suddenly and inexplicably turns black. The screen is still powered, and if I play with the volume controls, the volume indicator shows just fine.
The only way to resolve this is to press the home button, at which point I see the following message in my log:
SpringBoard[15] : Failed to snapshot WaveDeck
When I then open the app again, it's fine.
Can anyone shed some light on this?
Update from the WaveDeck front:
We've used applicationDidEnterBackground in the app's delegate in a bad way: asking all the background operations to finish up using beginBackgroundTaskWithExpirationHandler and keeping the main runloop running inside applicationDidEnterBackground.
That way the method of applicationDidEnterBackground came to an end only after finishing all background operations, whether the app became active again or not.
So apparently the OS could not 'snapshot' the app correctly and would put on a black screen some time after returning from background state - when the delegate function of applicationDidEnterBackground ended.
I encounter a similar issue. Put the long time save operation in next runloop, so applicationDidEnterBackground return immediately, the system's snapshot mechanism works correctly.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// don't block ios's snapshoting, avoid screen suddenly turns black
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(saveAppState) object:nil];
[self performSelector:#selector(saveAppState) withObject:nil afterDelay:0];
}
- (void)saveAppState
{
[self longtimeSave];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(saveAppState) object:nil];
}
The following code works fine from iOS 3.0 to iOS 4.3 simulator but crashes on iOS5
-(void)viewWillAppear:(BOOL)animated {
[self.tableView reloadData];
[super viewWillAppear:animated];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.navigationController viewDidAppear:animate];
}
I got exc_bad_access in [self.navigationController viewDidAppear:animate] and it makes the app crashes.
It works fine without any problem in the previous verison.
This app is developed in XCode4 with deployment target 3.0. My user just found the app crashes when he upgraded his iPhone with iOS5.
I am being able to reproduce theproblem but not sure how to fix it.
Can anybody shed some light?
[self.navigationController viewDidAppear:animate]; is the problem here. In iOS 5 it's going to recursively call this view controller's viewDidAppear method over and over until it just crashes. Why exactly do you need to call viewDidAppear manually on your navigation controller? If it's actually necessary to get your code working, you might want to backtrack a bit as something else must be wrong if you're needing to do this.
One other thing that's just good housekeeping: in your viewWillAppear, [super viewWillAppear:animated]; should come first it that method.
I pop up a UIAlertView to ask the user if they really want to open a URL. If they choose "Yes" my app immediately opens the URL and is sent to the background. When the user reopens my app (with multitasking) the alert view hasn't disappeared completely and is in a half-transparent state. Presumably the screenshot used in multitasking was taken before the alert view completely disappeared, but just after it began to fade away.
How can I give my app the extra second it needs to completely dismiss the alert view? It seems like I should do something in -applicationDidEnterBackground: or listen in the view controller for the equivalent notification but I'm not sure about the best approach.
You should call - (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated. In iOS 4 alert views are not dismissed automatically when an app moves to the background.
I've heard of this happening--the backgrounding screenshot happens in the middle of the animation of the thing that triggered the backgrounding.
You could use [self performSelector: withObject: afterDelay:] to insert a bit of time between the dismissal of the alert and the backgrounding of the app. withDelay is a float and accepts fractions of seconds, so you can fine tune it pretty nicely.
Just in case anyone else is looking for the code that worked for me, here it is:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1) { // Ok button
// URL to be opened
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"tel:%#", [self phoneNumber]]];
[alertView dismissWithClickedButtonIndex:buttonIndex animated:YES];
[[UIApplication sharedApplication] openURL:url];
}
}
In the app I am working on, I have action sheets and alert views which I would like dismissed when app enters the inactive/ background state.
I am using the UIApplicationWillResignActiveNotification instead of the UIApplicationDidEnterBackgroundNotification as I want the code to be compatible with iOS3.2.
-(void)applicationWillResignActive:(Notification *)notification{
if (self.actionSheet && self.actionSheet.visible){
NSLog(#" actionSheet is Visible");
[self.actionSheet dismissWithClickedButtonIndex:0 animated:NO];
}
}
Testing this in simulator (iphone 3.2, iOS4), with the actionSheet visible, I press the home button, but I do not get the "actionSheet is Visible" message. Yet when I re-open the app and dismiss it again with home button, I get the "actionSheet is Visible" message.
This suggests that the first time the actionSheet's visible property is not being set. Could there be a delay in the property being set? In fact I put a message in the method that displays the actionSheet
[self.actionSheet showInView:self.parentViewController.tabBarController.view];
if (self.actionSheet.Visible) NsLog(#" action Sheet visible");
even here I do not get the message. Where/ when is the visible property set? Am I doing something fundamentally wrong in trying to dismiss the actionSheet? I have seen similar very good and detailed solutions on dismissing alertViews in SO.... but they don't seem to cover this issue. Any help will be much appreciated.
Why would you even need to check if it's visible? In fact, why would you even need to check it against nil? You could just put [self.actionSheet dismissWithClickedButtonIndex:0 animated:NO];, and it should work fine, as if the action sheet exists you will dismiss it, and if it doesn't, you will will just call the method on nil, which does nothing.
I get this cryptic error the first time (and only the first time) my view is loaded due to the following line of code:
- (void)viewWillAppear:(BOOL)animated
{
[textField becomeFirstResponder];
}
There is a noticeable (~3 – 4 second, even on the simulator) delay due to this that makes my app feel unresponsive. Does anyone know how to fix this? I can't find any documentation on it on Apple's site, or any solutions here or on Google.
Strangely, the opposite situation happens if I put the line in -viewDidAppear: instead of -viewWillAppear:; that is, instead of printing the error only the first time the keyboard is shown and never again, the error is not printed the first time but every time after. This is causing a major headache for me.
Override -viewDidAppear:, not -viewWillAppear, and make sure to call [super viewDidAppear:]. You should not perform animations when you are not on screen ("will appear"). And the -viewDidAppear: docs explain that you must call super because they have their own things to do.
I was getting a similar error when quickly:
Dismissing a modal view
Updating the main view
Presenting a new modal view
I noticed I was only getting it in the simulator and not on the device. Additionally, I was getting caught in an infinite loop.
My solution was to delay the presenting of the new modal view. It seems that quickly updating the view hierarchy caused some sot of race condition in Apple's code.
With that in mind, try this:
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[textField performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.1];
}
You may be having issues presenting the keyboard for a UITextField that ins't yet on screen.
This may be causing problems similar to mine.
Also, you pause giving the hierarchy time to update before presenting the keyboard, just in case.
Hope this helps.
Check you are only interacting with the UI on the main thread. I got wait_fences: failed to receive reply: 10004003 while I was sitting there waiting for a UIAlertView to show for about 5 seconds because the relevant code was executed on a background thread. You can make sure by putting your code in block and sending it to the main thread:
dispatch_async(dispatch_get_main_queue(), ^{
if (!success) {
// Inform user that import failed
UIAlertView * importFailedAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"ErrorTitle5", #"Import failed")
message:NSLocalizedString(#"Error5", #"Something went wrong")
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK", nil)
otherButtonTitles:nil];
[importFailedAlert show];
}
});
After trying everything I could find on Google and none of it working, this is what solved the problem for me. The key is that I'm doing this stuff in the willDismissWithButtonIndex delegate method. Before I was doing it elsewhere.
- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
[myTextField resignFirstResponder];
[myTextField removeFromSuperview];
[myTextField release];
}
If you have the following line in viewDidLoad, it can cause this message. Comment the following line.
[[UIApplication sharedApplication] setStatusBarHidden:YES]; //This line should be commented
(You can disable the status bar from the application plist file instead).
After few tests the big rule is: "Do not perform animation before animated dismissal or animated show.".
For example:
do not call -dismissModalViewControllerAnimated:YES after the delegation callback of an UIAlertView -alertView:willDismissWithButtonIndex: (wait the fade out of the alert view before doing this using the -alertView:didDismissWithButtonIndex: callback)
do not try to show the keyboard (becomeFirstResponder) before your view controller is on screen.
Bad things may happen.
Hope it will be useful ;-)
This worked for me to get the keyboard to show itself immediately, without animation or delay.
Let textField be an instance variable of MyViewController (a subclass of UIViewController).
Call [textField becomeFirstResponder] in initWithNibName:bundle: (for a subclass of UIViewController) or initWithStyle: (for a subclass of UITableViewController), not in viewDidLoad. E.g.:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[textField becomeFirstResponder];
}
return self;
}
Or, call it just after initializing but before pushing the UIViewController. E.g.:
MyViewController *viewController = [[MyViewController alloc] init];
[viewController.textField becomeFirstResponder];
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
You have done [textfield becomeFirstResponder];
And after you get the value from textfield in your code, do [textfield resignFirstResponder];. That will help you, I think.
If you're running the current iPhone Simulator 4.0, this error message appears frequently when rotating the screen (or when animating after rotating the screen) accompanied by 1-2 second lag in the animations.
It is a bug in this version of the Simulator and should be fixed soon.
See here for more info: http://www.iphonedevsdk.com/forum/iphone-sdk-development-advanced-discussion/17373-wait_fences-failed-receive-reply-10004003-a.html
Your problem is related.
override viewDidappear, not viewWillAppear:
-(void) viewDidAppear:(BOOL) animated
{
[super viewDidAppear:animated];
[myTextField becomeFirstResponder];
}
I can simulate this one-on-one by means of this UIAlertView code.
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:NSLocalizedString(#"defineTitle",#"defineTitle")
message:NSLocalizedString(#"defineBody", #"defineBody")
delegate:self
cancelButtonTitle:NSLocalizedString(#"Ok", #"Ok")
otherButtonTitles:nil];
[alert show];
When the NSLocalizedString are not defined in the Localizable.strings file it will take
to long to search for the texts, so the alert will show and the “wait_fences: failed to receive reply: 10004003” will be shown.
For me I only had to add the texts to the Localizable.strings files and my problems were solved. Maybe this is also the case for other occurances?
Also with the UIAlertView. What solved it for me was having the resign as below, as warehouselabs mentioned earlier.
- (void)didPresentAlertView:(UIAlertView *)alertView
{
[txtListingPassword becomeFirstResponder];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[txtListingPassword resignFirstResponder];
}
The other delegates of UIAlertViewDelegate did not fix the issue.
The problems is that there's a race condition in Apple's code. Usually, this has to something to do with incorrect UI updates.
In my experience, you either haven't called the super in viewDidAppear, viewWillAppear etc. Or you try to display a UIAlertView in viewDidLoad or viewWillAppear.
When you add a UIAlertView, the framework needs a reference to your parent view. But if you're in viewWillAppear or viewDidLoad, the view isn't actually displayed... You should consider move the code to viewDidAppear where the view is ready to be used by UIAlertView.
Is the Text Field contained within that view, or within something else? You can only send the 'becomeFirstRepsonder' to something that is contained directly within that view. If it's stored in some other widget component, you shouldn't set the first responder status in this widget, but rather in the widget that's being created. For example, if you're adding the text field to an alert view, because the show happens asynchronously, it might not be up by the time you call the becomeFirstResponder. (Ideally, you'd have your own alert view class and define the text field within that, and when that view receives the viewDidAppear, you'd set the textfield as first responder at that point.)
I also get the message wait_fences: failed to receive reply: 10004003 and my viewWill... and viewDid... methods do nothing but send messages to super. In my case it happens when I have a UIAlertView showing in my GameViewController and the user instead presses the iPhone round device button and then returns to the app. This looks out of my hands.
Alertview or actionsheets should be shown on main threads...so if your making any synchronous connections and performing that operation on another thread and showin alerts on the basis of output you received from that operation then you will get this error message wait_fences: failed to receive reply: 10004003 . You can do something like....
[self performSelectotOnMainThread:#selector(handleOutput:) withObject:output waitUntilDone:YES/NO];
and show alerts in handleOutput method passing the output response string as the parameter.
Solution is here!
I had same error, now I got the solution, this may help you.
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
[self performSelector:#selector(YOUR_METHOD) withObject:nil afterDelay:0.1];
}