Dismissing Modal View Controllers - iphone

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];

Related

Dismissing modal view controller

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];

Dismissing 3 layers of modal view

In my application, I have three layers of modal view controllers.
1) So my rootViewController is a tabbar.
2) On applicationDidFinishLaunching I am presenting a viewController, say viewController A modally above tabbar.
3) On click of a button in 'viewController A', I present another viewController B modally.
4) And a button action on viewController B presents navigationController modally with its rootViewController as viewController C.
5) Finally from viewController C, I want to go back to viewController A.
I tried using
[[[self parentViewController] parentViewController]dismissModalViewControllerAnimated:YES];
in viewController C, but it reverts me back to viewController B instead of viewController A.
How can I revert back to viewController A.
Any help would be appreciated.
push all the 'modal' views on a navigationControl with a transitionStyle that looks like the modalTransitionStyle..dont reinvent stuff
present all in one modal navigationController Id say :)
You've got a complex VC stack. You could as one poster suggested implement a custom dismissView method, but that would be fragile: if you reuse this view, or move it in your app, it will cease functioning, because it relies too much on specific knowledge of how other VCs have configured their state.
You could configure a delegation chain. This would be the standard way to manipulate views: the presenting VC is also responsible for removing anything it presents.
To do so, build a protocol implemented by B, and initialize C with a reference to B. Similarly, initialize B with a reference to A (with potentially the same protocol, depending on any other communication that needs to be passed between them.)
Then when the button is clicked on C, it calls B's delegate method. B unwinds C as appropriate, and calls A's delegate method. A unwinds B as appropriate.
This has the advantage of keeping VC knowledge encapsulated: A knows how it presented B, so it knows how to unpresent it, and B knows how it presented C, and knows how to un-present it. In no case does one VC need to make assumptions about how it was presented by another.
Implement the view dismissing method like:
- (IBAction)dismissView
{
[self dismissModalViewControllerAnimated:NO]; // dismiss c
[[self parentViewController] dismissModalViewControllerAnimated:NO]; //dismiss b
}
[self parentViewController] will return the parent view of viewControllerC, that's viewControllerB. So it'll dismiss that view too.

Dismissing modalviewcontroller issue

What is the a way for the modal controller to talk to the presenting controller.
In my case i m presenting modalviewcontroller without using delegate. But want to dismiss modalviewcontroller using delegate protocol.
SO can i dismiss modalviewcontroller using delegate protocol where i m presenting modalviewcontroller without using delegate.
The modal controller can dismiss itself. Within the modal view controller, use [self dismissModalViewController animated:YES] (or NO if you don't want to animate it). If you include that line of code in the modal controller, then you should be okay!
dismissModalViewControllerAnimated:
The parent view controller is responsible for dismissing the modal view controller it presented using the presentModalViewController:animated: method. If you call this method on the modal view controller itself, however, the modal view controller automatically forwards the message to its parent view controller.
via iOS Documentation
You can also access the parent view controller through [self.parentViewController ...]

Canceling a modal view & app crashes

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

Problem dismissing multiple modal view controllers

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.