I am having trouble getting my modal view controllers to display properly. I have a parent view controller that is the delegate for modal view A. In modal view A I am presenting modal view B, and having the delegate dimiss modal view A.
When modal view B appears it seems to display but the screen dims, and the UI locks up, but the app doesn't crash. I set animation settings to NO and I am still getting the same issue.
Order of events:
Parent View show Modal View A
Modal View A shows Modal View B in Modal View A controller
Parent View dismisses Modal View A in Modal View A controller via delegation
This is where my UI hangs, I can see Modal View B but can't click on it, or do anything
You could use this
[[[self presentingViewController] presentingViewController] dismissModalViewControllerAnimated:YES];
A modal view controller must have a parent view controller in order to display. If you dismiss the parent view controller ("modal view A", in your case), behavior will be unpredictable.
If you're certain that nested modal view controllers are what you really want, you'll need to dismiss them in reverse order; wait until you're done with "B", then dismiss "B", then dismiss "A".
If you don't need the modal presentation style, you would be better off using a UINavigationController to maintain your stack of view controllers.
Update: here is how I would rearrange your order of events. Presented as code for clarity.
[parentView
presentViewController:modalViewControllerA
animated:YES]
[modalViewControllerA
presentViewController:modalViewControllerB
animated:YES]
[modalViewControllerA
dismissModalViewControllerAnimated:YES]
[parentView
dismissModalViewControllerAnimated:YES]
Solved by having my parentViewController act as the delegate. Here is my order:
[parentView presentViewController:modalViewControllerA animated:YES]
[parentView dismissModalViewControllerAnimated:YES]
[parentView presentViewController:modalViewControllerB animated:YES]
//Modal B dismisses himself
In my delegate method, I needed to make sure that I dismissed Modal A before presenting Modal B
For iOS 6+ and - presentViewController:animated:completion:
[[[self presentingViewController] presentingViewController] dismissViewControllerAnimated:YES completion:nil];
in Swift 2.1
you can try
self.presentingViewController?.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
works for me
View A -> View B -> View C
Apply this code in view C , you will be landing to View A
I have a main view and need to show a modalview1 where a button present a modalview2. Looks the same you needed.
But there is a button in the modalview2 which forwards to the main view.
So the solution is:
Main view presents UINavigationController with modalview1 as rootController. Then modalview1 present modalview2 by "[self.navigationController modalview2 animated:YES];".
When modal2 needs to forward to the main view, just make "[self.parentViewController dismissModalViewControllerAnimated:YES];" and UINavigationController is hidden.
Hope it's clear.
Simple:
Dismiss all views:
[self dismissModalViewController animated:YES];
[self dismissModalViewController animated:YES];
[self dismissModalViewController animated:YES];
[self dismissModalViewController animated:YES];
(one for each added modal view)
then present a new modal view controller
may be after long but.. I am in same problem and this is the only post with some answer.
I am not getting what you mean by setting delegate of a parentViewController to self is not allowed .
what I am doing right now is
[self presentModalViewController:ViewControllerA animated:YES];
[self dismissModalViewControllerAnimated:YES];// inside ViewControllerA
[self presentModalViewController:ViewControllerB animated:YES];
[self dismissModalViewControllerAnimated:YES];// inside ViewControllerB
Problem is after viewControllerA , viewControllerB view is not presenting.
Thanks,
Apple document about dismiss(animated:completion:) method.
In section Discussion, it said:
any intermediate view controllers are simply removed from the stack.
If you present several view controllers in succession, thus building a stack of presented view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack.
In other words, if the view controller stack like following
Root -> A -> B -> C -> D ... -> Z
D calls dismiss method, all view controllers behide D, ex: (E ... Z), will be removed from the stack.
Related
Issue: When dismissing a modal view controller, the header on the presenting view controller is moved up (what looks to be around 20 pixels).
Steps to recreate:
Create a tab bar controller (T), inside create a navigation controller with (N) a root view controller (A).
Setup another view controller (B) (this is the view controller to be presented modally) with a delegate so we can notify the presenting view controller (A) when it should dismiss the modal (B).
Inside the navigation controller's root view controller(A) create an instance of (B) by instantiating it from the storyboard with it's storyboard id, then present (B) with [self.tabBarController presentViewController:(B) animated:YES complition:nil];.
Have a button on (B) that when pressed triggers the delegate function to notify (A) to dismiss (B) by using [self.tabBarController dismissViewControllerAnimated:YES complition:nil];
So far all works as expected. However once the modal view controller (B) is dismissed. The navigation header on (A) is moved up about 20 pixels.
I cannot figure out why the navigation header is moving up when the modal is dismissed.
In the presenting viewController add following code to the
-(void)viewDidAppear:(BOOL)animated method:
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
I have a UITabbarController with a UINavigationController. The view in the NavigationController presents an MVC (AddClockNavigationController). This MVC has a nib with an view and an UINavigationController. The NavigationController.view is added as an subview to the MVC's view.
The NavigationController in my MVC has two buttons, an Cancel and an Done. When pressing either one of them the MVC should be dismissed.
The IBActions of these buttons are in the UINavigationController's view (AddClockViewController), but whenever pressing them the MVC does not dissappear.
If I put the actions into the MVC, it does disapear.
If I put the function in my MVC and call it from my viewController using [self.parentViewController myFunction] it does not disappear.
How can I get it to disappear from my view?
I guess my explenation is quite messy but I hope you understand it.
A view from my IB:
Best regards,
Paul Peelen
Edit
I have tried this with [self dismissModalViewControllerAnimated:YES];, [self.parentViewController dismissModalViewControllerAnimated:YES];, [self.navigationController dismissModalViewControllerAnimated:YES];, [self.parentViewController.navigationController dismissModalViewControllerAnimated:YES]; and, as stated, with a function in the parentView dismissing it. Nothing works.
When some view controller presents another one, it becomes a parent view controller. So if you want to dismiss your modal view controller, then you have to choices:
from the parent view controller call
[self dismissModalViewControllerAnimated: YES];
OR
from the modal view controller call
[self.parentViewController dismissModalViewControllerAnimated: YES];
You actually don't need the navigation controller (cause you don't push/pop any view controllers). Just add the UINavigationBar to your MVC and place buttons on it. Then add actions to them and do choice #2.
Your code is not working because navigation controller has no parent, as it wasn't presented as modal.
One situation is that dismiss{Modal}ViewControllerAnimated is called before presented viewController's viewDidAppear is called. In such situation, the presented is presented with animated == YES. and before the presented is fully appeared, it got dismissed.
To fix it, you need to check at the point of time for dismissing, check if viewDidAppear is called, if not, defer the dismissing in - viewDidAppear.
I have a confusion on canceling the modal views:
Case 1: I have a navigation view controller and I am presenting a modal view controller from this navigation view controller. Now, when I am to cancel this modal view from where should I call the dismissModalView method -- navigation view controller or the modal view controller?
Case 2: I have a modal view controller and I am presenting another modal view controller from first modal view controller. Now, when I am to cancel second modal view from where should I call the dismissModalView method -- frist modal view controller or the second modal view controller?
Will canceling it from a wrong place cause a app crash also?
An advisable way to handle modal view controllers is to us notifications to inform the class that presented it to release it. Generally, you use code similar to this to show a modal view.
SomeClass *yourViewController = [[SomeClass alloc] initWithNibName:#"SomeClass" bundle:nil];
[self presentModalViewController: yourViewController animated: YES];
[yourViewController release];
With the above code, your modal view should end up with a retain count of 1. When you dismiss it, the parent view will release it and it will be purged from memory. Your "close" button in your modal view should execute code that looks like this:
- (void)dismissSelf{
[[NSNotificationCenter defaultCenter] postNotifivationName:#"I'm done" object:self];
}
Back in your parent viewcontroller, ou should listen for this notification and then dismiss the modal view when the notification is posted.
That said, to answer your questions:
A modal view controller never dismisses itself. Post a notification and then let the navigation controller handle it.
You can't dismiss the first modal view until the second one has been dismissed. If you do, you will get a EXC_BAD_ACCESS error. Think of the second modal view as "inside" the first one. If the first is dismissed, the second one will be dragged away with it, but it hasn't been dismissed.
you should dismiss the modal view
controller.
you should dismiss it from the
second modal view controller.
the app crashes because when you trying to dismiss the modal view controller , the scope of corresponding view controller is lost, may be u released the view controller before dismissing
You always dismiss the modal view from the controller, where you presented it (with dismissModalViewControllerAnimated). So:
in the navigation controller
in the first modal view controller
I have a view controller with the following method:
- (IBAction)pickLocation:(id)sender{
SearchLocationPickerViewController *modalView = [[[SearchLocationPickerViewController alloc] init] autorelease];
[modalView setModalTransitionStyle:UIModalTransitionStylePartialCurl];
modalView.searchVC = self;
[self presentModalViewController:modalView animated:YES];
}
This transitions perfectly fine, and displays the modal view controller as expected. However, when I dismiss the modal view using the following (executed from the modal view controller):
- (IBAction)closeLocationPick:(id)sender{
[self dismissModalViewControllerAnimated:YES];
}
The modal view transitions out as expected, but right at the end of the transition, the display will really quickly flicker SOMETIMES. It displays the modal view that was just displaying for a fraction of a second. This only happens maybe every three out of ten times of showing / hiding the modal view.
Any ideas on what could be causing this?
If I am reading your post correctly, one problem may be that you are dismissing the modal view from within itself. While this does work, it is not the way in which Apple prefers. I am making the inference that this may muck with the animation of the view as it is dismissed.
Your IBAction should be calling a delegate method in the modal view controllers parent, the one that created and presented the modal view controller originally. You define the delegate protocol in your modal view controller and adopt it in the view controller that makes the presentModalViewController: call.
Here are the relevant Apple docs on dismissing a model view.
View Controller A presents View Controller B modally, which has a button to present View Controller C modally.
Here is my flow:
A presents B which presents C
When B presents C, I want B to be dismissed, so my only view controllers are A and C. I am not sure where to call:
[self dismissModalViewControllerAnimated:NO];
in order to dismiss B.
I created a delegation pattern, where right after B presents C, A will dismiss B however nothing gets dismissed.
If B is C's delegate then C dismisses itself.
I think you can use NSNotificationCenter.
You can make a NSNotificationCenter at B that calling a method to dismiss itself, then make a post Notification from C to call the NSNotificationCenter at B.
I'm not sure of it, but it may works.
In B add:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(dismissFunction:) name:#"DismissFunction" object:nil];
and the method like this:
- (void)dismissFunction:(NSNotification*)notification
{
[self.navigationController dismissModalViewControllerAnimated:YES];
}
And in C add:
[[NSNotificationCenter defaultCenter] postNotificationName:#"DismissFunction" object:nil];
You should use a UINavigationController to do this.
*create a navigation controller with controller B as the root view controller.
*A present the navigation controller as a modal with presentModalViewControler:animated: this will have the same affect as presenting B
*When B needs to present C it pushes it ti the navigation view comptroller's stack by calling [self.navigationController pushViewController:C animated:YES]
*if C needs to be dismissed to revile B you can do those by calling [self.navigationController popViewControllerAnimated:YES]
*If C needs to dismiss and revile A you can dismiss the modal by calling [self.navigationController.parentViewController dismissModalAnimated:YES]
you could go 1 step further and not use a modal at all by embedding A as the root view controller of a navigation controller and pushing B to the Navigation controller instead of presenting it as a modal
I think that you can not do it. Read again the documentation for dimissing the modal view controller
If you present several modal view controllers in succession, and thus build a stack of modal view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack.
That means if you dismiss B, you will dismiss C as well
just do this from A
[self.navigationController dismissModalViewControllerAnimated:YES];