How to dismiss a viewcontroller within another ViewController? - ios

Let say I have view controllers named A,B,C,D,E I open theseViewConrollersone after the other in presentModel way. When I am in ViewController E I want to open another ViewController F in presentModel way. In that F ViewController I have a back button. When I click on that It should dismiss the F and show the A ViewController. But now when it dismissse shows E. How can I dismiss all other viewcontrollers except the A when I click the back button of F
Please help me. Thanks
UPDATED
-(IBAction)dismisthis:(id)sender{
UIViewController *dismissingViewController = self.presentingViewController;
while (dismissingViewController.presentingViewController != nil && [dismissingViewController isKindOfClass:[FrontViewController class]]) {
dismissingViewController = self.presentingViewController;
}
[dismissingViewController dismissViewControllerAnimated:NO completion:NULL];

If you dismiss a view controller that is presenting another view controller, the entire hierarchy is dismissed. It doesn't matter how many levels there are. So all you have to do is find your view controller A and tell it to dismiss its presented view controller.
If A is always the bottom of the heap, you can use a simple loop to find it:
UIViewController *dismissingViewController = self.presentingViewController;
while (dismissingViewController.presentingViewController != nil) {
dismissingViewController = self.presentingViewController;
}
[dismissingViewController dismissViewControllerAnimated:YES
completion:NULL];

What about sending Notification using NSNotificationCenter from F and A will listen to it. Once A receives the notification, it will call dismissViewController which I think will dismiss all.

At this moment i can think of three solutions
You should keep track of all viewControllers in a stackObject(which is an array) in Appdelegate. When you want it access this get these array and dismiss all view controler objetcs.
Each viewcontroller you can observer for a NSNotification which will listen for notification. When you need it in "F" just post the notification and this notification will dismiss the eviewcontrollers
Go for NavigationController so that you can push to rootviewcontroller

Try this:
UIViewController *rootVC = [UIApplication sharedApplication].delegate.window.rootViewController;
[rootVC dismissViewControllerAnimated:YES completion:nil];
// One-liner
// [[UIApplication sharedApplication].delegate.window.rootViewController dismissViewControllerAnimated:YES completion:nil];

Make A as rootViewController and use below code on Back button of "F":
[[[[UIApplication sharedApplication] keyWindow] rootViewController] dismissViewControllerAnimated:true completion:nil];

Related

DismissViewControllerAnimated is not working

Working with local push notifications if the notification receives its move to NotificationViewcontroller there is no notification it moves the main view controller .
Here I'm using code:
- (void)applicationWillEnterForeground:(UIApplication *)application
{
if ([status isEqualToString:#"YES"])
{
NotificationViewcontroller *notify_view =[[NotificationViewcontroller alloc]init];
[self.window.rootViewController presentViewController:notify_view animated:YES completion:nil];
when i use this code means it should not move to NotificationViewcontroller i got this errorr:
whose view is not in the window hierarchy!`
// self.window.rootViewController=notify_view;
i use this code it move to NotificationViewcontroller. after seeing the notification put one back button to go view controller
NSLog(#"Go to some other view");
}
else
{
[self.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
}
After see the notification put one back button to go view controller that back button is not working.
-(IBAction)back_btn:(id)sender
{
[self.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
}
You are setting the rootviewcontroller as NotificationViewcontroller , so on press of back button change the rootviewcontroller as some other view controller.
Because there is no view hierarchy, to dismiss the view controller.
presentviewcontroller is used to open new viewcontroller from existing viewcontroller, then only you can dismiss your presentedviewcontroller and it will go back to your parent(e.g.) viewcontroller.

Pop THE RootViewController

I am developing an app that as first viewcontroller has an UIViewController.
This controller pushes a NavigationViewController that contains other controllers.
Now I need to pop the RootViewController of the NavigationController to go back to the initial UIViewController.
I tried with
[self dismissViewControllerAnimated:YES completion:nil];
and the app crashes("Tread1:EXC_BAD_ACCESS(code=1, address= ......)").
I tried with
[self.navigationController popViewControllerAnimated:YES];
and nothing happens.
The initial UIViewController calls
[self performSegueWithIdentifier:#"MyIdentifier" sender:self];
In the UIBuilder the segue is of type "Show(e.g. Push)"
Then I have a NavigationViewcontroller that contains the RootViewController and another Viewcontroller.
What I am trying to achieve is to go back to the first viewcontroller (the one outside the navigationcontroller) from the RootViewController. So I should have the navigationcontroller there.
What am I missing?
Apparently I had a couple of GestureRecognizer still in place that were causing the crash of the app.
The right method was:
[self dismissViewControllerAnimated:YES completion:nil];

How do I present a ViewController over another with that VC having no knowledge of the new one?

I had a method to do this, but it stopped working at some point.
The motivation here is for debugging. I have a button that shows a debugging action sheet from whatever VC calls it. This works great. However, in the action sheet, after I select one, the action wanted is in some cases the presentation of a new VC. The first example of this was a VC that displays my internal log. It's very valuable when not debugging in a "tethered" mode.
Each debugging VC is represented as a scene in the Main storyboard. I instantiate the VC with instantiateViewControllerWithIdentifier:. Then I am trying to get it presented.
The tricky part is that the new VC has to be presented and then dismissed without writing any code in the VC that is currently active. Neither do I want to create a Segue from every VC where this might be called. The whole point is that the DebugActionSheet is self contained except for the single call to fire it up.
You should be able to access the top most view controller like this from your ActionSheet delegate method.
+ (UIViewController*) topMostController
{
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
return topController;
}
then in the calling code:
[MyDebugController.topMostController presentViewController:myLoggingView
animated:YES
completion:nil];
and your myLoggingView can dismiss itself by calling
[self.presentingViewController dismissViewControllerAnimated:YES
completion:nil]
Try presenting it on the main thread?
dispatch_async(dispatch_get_main_queue(), ^ {
[self presentViewController:vc animated:YES completion:nil];
});
It turned out my problem was that the current top controller is using a Navigation controller, so the required code is different.
UIStoryboard *story = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
_paletteVC = [story instantiateViewControllerWithIdentifier:#"PaletteDisplayVC"];
[[_delegate navigationController] pushViewController: _paletteVC
animated: YES];
I pass the current top controller to my DebugActionSheet as delegate, so I do not need the topMostController method above. However, I presume it would work with that also.

Can a presented view controller also be a presenting view controller?

On top of an existing view I want to:
a) display a screen to the user
b) then send an SMS
c) display another screen to the user.
For a) I am doing this:
[[UIApplication sharedApplication].delegate.window.rootViewController presentViewController: firstController animated: NO completion:nil];
and for b) I am doing the same thing, except this is presenting a different vc of course, a MFMessageComposeViewController.
However in order for b) to appear I first have to dismiss the first view controller using:
[[UIApplication sharedApplication].delegate.window.rootViewController dismissViewControllerAnimated:NO completion: nil];
That works so far, I can see the first view appear then see the SMS compose view appear.
When the SMS is sent I am doing this to dismiss the SMS compose view
[[UIApplication sharedApplication].delegate.window.rootViewController dismissViewControllerAnimated:NO completion: nil];
But then nothing happens when I try to present another screen to the user using presentViewController. I can't see any reason why this should be, is there something I'm not aware of?
Actually the screen before the SMS view and after it are the same except they have different text, so the easiest sequence of steps would be:
a) present the view controller with text "abc"
b) present the SMS controller
c) when the SMS is sent dismiss the SMS controller
d) update the text in the first view controller using an IBOutlet
e) dismiss the first view controller.
However as mentioned earlier on, if I don't dismiss the first view controller the SMS controller will not appear. So my main question is how can I present the SMS controller on top of the first view controller?
You can either present one after the other closes:
UIViewController *rvc = [UIApplication sharedApplication].delegate.window.rootViewController;
[rvc dismissViewControllerAnimated:NO completion:^{
[rvc presentViewController: secondController animated: NO completion:nil];
}];
Or present another on top:
UIViewController *rvc = [UIApplication sharedApplication].delegate.window.rootViewController;
UIViewController *pvc = rvc.presentedViewController; // you may need to loop through presentedViewControllers if you have more than one
[pvc presentViewController: secondController animated: NO completion:nil];
I just tried it on iOS15. Yes a presented VC can present another VC.
So suppose you have:
VC1 --> present--> VC2
you can easily call present(VC3(), animated: true, completion: nil) on VC2 and things would work fine. You can happily end up with:
VC1 --> present--> VC2 --present--> VC3
FWIW when you dismiss VC3, it will only go back to VC2. It won't go back to VC1.
iOS does not allow you to open two modal views at the same time. The modal view is designed to be the topmost view.
In my case, I have access directly to the presented view controller so in that case:
self.present(viewControllerToPresent, animated: true) {
//It's presented.
}
extension UIViewController{
/// most top presented view controller
var presentedTop:UIViewController {
var ctrl:UIViewController = self;
while let presented = ctrl.presentedViewController {
ctrl = presented;
}
return ctrl;
}
}
// call somewhere someCtrl.presentedTop.present(vc, animated:true)

IOS: dismiss two viewController

I have three viewController
First, Second and Third
from Second to open Third I use
Third *third = [[Third alloc]initWithNibName:#"Third" bundle:nil];
[self presentModalViewController:third animated:YES];
[third release];
Now I want return from third to first; then I set in viewDidAppear in second this code:
[self dismissModalViewControllerAnimated:NO];
but for 1 second I see Second and I don't want watch it...how can I do?
You need to dismiss third view controller first and then second Viewcontroller. Do the following code when you want to go first view controller.
-(void)goToFirstView{
UIViewController *vc = [self parentViewController];
// UIViewController *vc = [self presentingViewController]; //ios 5 or later
[self dismissModalViewControllerAnimated:NO];
[vc dismissModalViewControllerAnimated:YES];
}
How is the Third modal view being dismissed in the first place? Perhaps by the user touching a 'Done' button? If so, it is in the handler for the button that you want to dismiss both.
You can dismiss both as:
[self dismissModalViewControllerAnimated: YES];
[self.presentingViewController dismissModalViewControllerAnimated: NO];
This happens coz viewDidAppear is called everytime before the view appears so as soon as it appears you dismiss it and it disappears..
I don't think what u are trying to do can be achieved with modalViewControllers...
instead use a navigationController and keep adding your viewcontrollers onto the stack and when you want to goto the First view controller just call
[self.navigationController popToRootViewControllerAnimated:YES];
EDIT:
just thought of it this can be achieved by using delegation.. you make second the delegate of third and as soon you dismiss the thirdviecontroller send the delegate a message.In this message call [self dismissModalViewControllerAnimated:NO];..
and you are done.. (pretty easy if you know delegation.)

Resources