I am getting this cryptic message: wait_fences: failed to receive reply: 10004003
I have googled and people think it has something to do with not properly dismissing a UITextField or Alert. I have one textfield in my app and I assure you I release it properly using resignFirstResponder, etc...
I get this message when I am opening a MPMusicPickerController from a subview, does that make any difference. I really need to get this fixed because it is messing up my whole app!
Thanks,
Brad
Edit1:
- (IBAction)openMediaPicker:(id)sender {
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeAny];
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = YES;
mediaPicker.prompt = #"Select songs to play";
[self presentModalViewController:mediaPicker animated:YES];
[mediaPicker release];
}
// Media picker delegate methods
- (void)mediaPicker: (MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection {
AppAppDelegate *appDelegate = (AppAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.tr2 stop];
[playstopButton setHidden:NO];
[playstopButton setImage:[UIImage imageNamed:#"Stop-Music-Button.png"] forState:UIControlStateNormal];
// We need to dismiss the picker
[self dismissModalViewControllerAnimated:YES];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
// Assign the selected item(s) to the music player and start playback.
[self.musicPlayer stop];
[self.musicPlayer setQueueWithItemCollection:mediaItemCollection];
[self.musicPlayer play];
}
- (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker {
// User did not select anything
// We need to dismiss the picker
[self dismissModalViewControllerAnimated:YES];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
}
Generally:
You should not do any animations in viewWillAppear only in viewDidAppear. Only prepare your data, outlets etc. in viewWillAppear.
Also a very common case where wait_fences might arise is when you have an animated dialog (Like your MPMediaPickerController) that causes another animated view to appear (Like a custom modal UIViewController) or the like, in which case you need to "postpone" the presentation of the second viewcontroller like this:
[self performSelector:#selector(showMyOtherViewController)
withObject:nil
afterDelay:0.1];
Also check out this answer https://stackoverflow.com/7194182.
Edit
A good way to "debug" conflicting animations is to simply set the animation to NO so in your code instead of
[self presentModalViewController:mediaPicker animated:YES];
[self dismissModalViewControllerAnimated:YES];
Simply do:
[self presentModalViewController:mediaPicker animated:NO];
[self dismissModalViewControllerAnimated:NO];
and check if the wait_fences error goes away and the correct behaviour (but without animation) is achieved. If this is the case you need some of the performSelector:withObject:afterDelay:-magic.
Edit: Please note that you can do the following in iOS 5.0:
[self dismissViewControllerAnimated:YES completion:^{
[self presentViewController:anotherViewController animated:YES completion:NULL]
}
That means that first, the currently presented View Controller (e.g. a ModalViewController) is dismissed and when the animation is finished you can invoke another block. In this case show another UIViewController
I also noticed that replacing clickedButtonAtIndex: with didDismissWithButtonIndex: when using UIActionSheet or UIAlertView seems to make the error message go away.
Related
I'm attempting to do a presentViewController with an UIImagePickerControl in order to display a standard Camera Roll photo picker. This works end-to-end in most of my app. The place where it does not work is when I want to use the imagePicker inside an already presented viewController; the view to present the album is unable to be presented.
The basic idea is I'm trying to either access the rootViewController on the window object, or the app delegate's persisted tabBarController (which is the rootViewController); both as examples of top level items that are hopefully always present. Just using "self" otherwise ends up as a partial view presenting it.
Is there a reliable way to presentViewController inside an already presentedView?
dispatch_async(dispatch_get_main_queue(), ^ {
// 1. attempt that works well elsewhere in app
[((AppDelegate*)[[UIApplication sharedApplication] delegate]).tabBarController presentViewController:self.imagePickerController animated:YES completion:nil];
// 2. this does nothing, no crash or action (_UIAlertShimPresentingViewController)
[[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController:self.imagePickerController animated:YES completion:nil];
// 3. attempt off related internet suggestion, nothing happens
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
[topController presentViewController:self.imagePickerController animated:YES completion:nil];
});
Because presentViewController is meant as a modal presentation, I don't think it's possible to present a second modal at the same time in the same UIWindow. You could, however, add a new UIWindow and present it there.
originalWindow = [[[UIApplication sharedApplication] keyWindow];
tempWindow = [[UIWindow alloc] init];
UIViewController *controller = [[UIViewController alloc] init];
tempWindow.rootViewController = controller;
[tempWindow makeKeyAndVisible];
[controller presentViewController:self.imagePickerController animated:YES completion:nil];
You'll want to add something like this in your response to the image picker's return:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// Process the result and then...
[self cleanupWindow];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[self cleanupWindow];
}
- (void)cleanupWindow {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(madeKeyWindow:) name:UIWindowDidBecomeKeyNotification object:nil];
[originalWindow makeKeyAndVisible];
}
- (void)madeKeyWindow:(NSNotification *)notification {
[tempWindow removeFromSuperview];
tempWindow = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIWindowDidBecomeKeyNotification object:nil];
}
What I need
I'd like to show an UIAlertView "Loading..." when I tap on a tab in my tabBar.
Reason why I want to do that
This is because that particular tab contains a UIWebView and is very slow, so when I tap on that tab it seems like my app is doing absolutely nothing for a few seconds. It is very ugly, so I'd like to show something to make the user know that the app is actually working.
Questions
In which position do I have to put it? If I write it in the ViewDidLoad, the AlertView is shown after those orrible few seconds. Is AlertView the best choice?
Thank you all.
add MBProgressHUD to your UIWebView viewDidLoad method
- (void)viewDidLoad {
[super viewDidLoad];
self.webView.delegate = self;
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = #"Loading...";
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[hud hide:YES];
}
UIAlerView is not a good idea.
//Delegate method of UIWebView
- (void)webViewDidStartLoad:(UIWebView *)webView
{
if(![[UIApplication sharedApplication] isNetworkActivityIndicatorVisible])
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
}
}
//Delegate method of UIWebView
- (void)webViewDidFinishLoad:(UIWebView *)webView_
{
if([[UIApplication sharedApplication] isNetworkActivityIndicatorVisible])
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
}
Set your tabBar as a delegate on viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
//Setting tabBarController as a delegate
self.tabBarController.delegate = self;
}
On your interface at .h method add delegate <UITabBarControllerDelegate>
Implement this function and add your loading view, for each time that you press tabBar. The method below gets executed always when the user taps an item on tabbar.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
//Show loading form here
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Do something...
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
});
});
}
P.S You need to add this method and set to delegate to every viewController which you need to show the alert view (Loading View)
For a loading view you can also load use MBProgressHUD as KingBabar pointed out. It has great features.
I have a UIAlertView that launches an email and a messages screen. When a user clicks on the Alert's button, both views open, however, they do not close.
I have a tried adding:
-(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
[self dismissModalViewControllerAnimated:YES];
}
to the body of the class, however, it did not help.
Here is how the email is presented:
[viewController presentViewController:email animated:YES completion:nil];
Edit Here is the entire code I am using to present the email:
//send email...
-(void)sendEmail{
//mail composer
Class mailClass = (NSClassFromString(#"MFMailComposeViewController"));
if(mailClass != nil){
if([mailClass canSendMail]){
//get the current view controller from the App Delegate
apptester_appDelegate *appDelegate = (apptester_appDelegate *)[[UIApplication sharedApplication] delegate];
UIViewController *viewController = [appDelegate getViewController];
MFMailComposeViewController *email = [[MFMailComposeViewController alloc] init];
email.mailComposeDelegate = self;
//navigation bar color depends on iOS7 or lower...
if(floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1){
[[email navigationBar] setTintColor:[UIColor blackColor];
}else{
[[email navigationBar] setBarTintColor:[UIColor blackColor]];
}
//show the model view...
[viewController presentViewController:email animated:YES completion:nil];
}
}
}
Has anyone else experienced this error?
This may not be relevant, but this app has a tab bar.
Make sure you have set delegate for mail controller
mail.mailComposeDelegate = viewController;
Also try this as well,
[viewController.tabBarController presentViewController:email animated:YES completion:nil];
Have you try this method and pass "controller" instead of self:
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
[controller dismissViewControllerAnimated:YES completion:nil];
}
Thanks!
It is the responsibility of presenting controller to dismiss the modal view. Make sure you implement the delegate of the modal in the presenting controller.
Two things:
1) Make sure you set the mailComposeDelegate on the MFMailComposeViewController before you present it.
2) In your mailComposeController:didFinishWithResult:error: method, you should do:
[controller dismissModalViewControllerAnimated:YES];
In iOS 6, I was using the following code to push a UIImagePickerController, of source type UIImagePickerControllerSourceTypeCamera, and to show its navigation bar. I wanted to show the navigation bar because after taking the image, I'm pushing another VC that allows the user to set some attributes in the database.
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
cameraController = [[UIImagePickerController alloc] init];
cameraController.delegate = self;
cameraController.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:cameraController animated:YES completion:NULL];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
cameraController.topViewController.title = #"Add";
cameraController.navigationBar.translucent = NO;
cameraController.navigationBar.barStyle = UIBarStyleDefault;
[cameraController setNavigationBarHidden:NO animated:NO];
}
In iOS 7 this code no longer shows the navigation bar. Does anyone know if there's a way to to get the navigation bar back for UIImagePickerController, of source type UIImagePickerControllerSourceTypeCamera?
Guess what? When imagePicker presents, it's automatic set to hidden....
All you need to do is setHidden:NO in next runloop. Like:
[self presentModalViewController:imagePicker animated:YES];
[self performSelector:#selector(showNavigationBar:) withObject:imagePicker afterDelay:0];
- (void)showNavigationBar:(UIImagePickerController*)imagePicker {
[imagePicker setNavigationBarHidden:NO];
}
#LeverkusenFan's solution works well. But instead of using a hack such as a run loop, you use the completion handler of presentViewController to achieve that effect.
[self presentViewController:cameraController animated:YES completion:^{
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
cameraController.topViewController.title = #"Add";
cameraController.navigationBar.translucent = NO;
cameraController.navigationBar.barStyle = UIBarStyleDefault;
[cameraController setNavigationBarHidden:NO animated:NO];
}];
In fact a better solution that avoids the weird animation when the navigation bar shows up and which works well when you press the back button on the nav bar is as follows:
In the delegate for the UIImagePickerController implement the following function.
- (void) navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (navigationController == self.cameraController && navigationController.viewControllers.count == 1) {
// When showing the ImagePicker update the status bar and nav bar properties.
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
navigationController.topViewController.title = self.cameraTitle;
navigationController.navigationBar.translucent = NO;
navigationController.navigationBar.barStyle = UIBarStyleDefault;
[navigationController setNavigationBarHidden:NO animated:animated];
}
}
This function will get called when the ImagePicker is shown and we only make the changes for the rootViewController of the ImagePicker (i.e. the camera screen).
I read a lot of documentation about this before i decided to ask.
So I have navigationController in my app. When user enters the first time in my app I do this
RegViewController *opr = [[RegViewController alloc] init];
self.regController = opr;
[self.navigationController presentModalViewController:self.regController animated:NO];
[opr release];
And it works fine. But when I click OK button in RegViewController I call this method
-(IBAction)btn_regPressed:(id)sender
{
NSLog(#"start to dissmis modal");
[self.navigationController dismissModalViewControllerAnimated:YES];
//[self.navigationController.parentViewController dismissModalViewControllerAnimated:YES];
}
But this code doesn't want to dismissModalViewController
Can somebody help me with thios issue please. Thanks
try to change your call to (remove the navigationController):
[self presentModalViewController:self.regController animated:NO];
and in your button (remove the navigationController):
[self dismissModalViewControllerAnimated:YES];
You are telling to your navigationController dismiss your modal, but your viewcontroller should do it.
Navigation controllers are used to navigation (go and back) purposes. And probably, your navigationController is nil.
In your RegViewController, try to dismiss self like so:
-(IBAction)btn_regPressed:(id)sender
{
NSLog(#"start to dissmis modal");
[self dismissModalViewControllerAnimated:YES];
}