How to dimiss the top most viewcontroller only in iOS? - ios

I have a situation like this:
Controller A present ControllerB present ControllerC.
Now I want to dismiss Controller C
But When I call [ControllerC dismissViewControllerAnimated]. Both ControllerB and ControllerC are dismissed .
How to dismiss ControllerC only

[ControllerB dismissViewControllerAnimated:YES completion:nil];
Or in cases where you don't have reference to the presenting view controller:
[ControllerC.presentingViewController dismissViewControllerAnimated:YES completion:nil];

Related

iOS: how to detect if viewcontroller appears after pop or dismiss

I have a view controller VC1 and I am doing following two operations on it:
Push another view controller VC2 from VC1's navigation controller by calling
[VC1.navigationController pushViewController: animated:YES];
Present another view controller VC3 from VC1 by calling.
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:VC3];
[VC1 presentViewController:navController animated:YES completion:nil];
Now when I am coming from VC2 to VC1 I am calling
[VC2.navigationController popViewControllerAnimated:YES];
and from VC3 to VC1 I am calling
[VC3.navigationController dismissViewControllerAnimated:YES completion:nil];
My question is when I am coming back to VC1 how do I know that whether I am coming from VC2(by dismissing) or VC3(by popping)?
Note: VC1 is loaded as child view controller inside a parent view controller VC4.
The best way would be to have the childViewController call back to the presenting view controller. By doing this the childViewController will not need to know the implementation details of whether it was presented modally or in a navigation stack etc.
With blocks it would look something like
#interface VC2 : UIViewController
#property (nonatomic, copy) void (^completion)(VC2 *viewController);
#end
You would set this block up something like this
VC2 *viewController = VC2.new;
viewController.completion = ^(VC2 *viewController) {
[viewController.navigationController popViewControllerAnimated:YES];
};
[VC1.navigationController pushViewController:viewController animated:YES];
Now where you was previously calling
[VC2.navigationController popViewControllerAnimated:YES];
You instead call
self.completion(self);
You put any logic you want to be associated with coming back from a specific viewController inside the completion handler

Dismissing previously presented modal view controller before currently visible one

I have 2 UIViewController's presented with [self presentViewController:viewController animated:YES completion:nil];, I want to dismiss the first one of them, without animation (It's not visible to the user anyway) and when the second one (currently visible) will be dismissed, the user will see the parent view controller who present them both.
- Parent
- First -> Dismiss first without animation
- Second -> Dismiss second with animation
How can I do that?
With your current view controller hierarchy if first view controller will be dismissed it will dismiss second view controller automatically. If you don't want that behaviour than make parent present second view controller. You can do that from first view controller by using [self.presentingViewController presentViewController:secondViewController animated:YES completion:nil]
Why do you want to do this?
You should do it like this for cleaner view hierarchy and better user experience:
Present first view controller :
[self presentViewController:viewController1 animated:YES completion:nil];
Dismiss first & present second view controller :
__weak MyViewController *aBlockSelf = self;
[self dismissViewControllerAnimated:YES completion:^{
[aBlockSelf presentViewController:viewController2 animated:YES completion:nil];
}];

dismissViewController clear the screen but doesn't dismiss

I have 2 screens:
The first call the second with the following code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:kDetailSegue]) {
[NSThread detachNewThreadSelector:#selector(loadingThread) toTarget:self withObject:nil];
TagDetailControllerViewController* detailController = segue.destinationViewController;
detailController.location = self.recentLocation;
}
}
The kDetailSegue is a present modally - presentation default - transition: default
In second ViewController, I'm trying to dismiss the screen:
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
It is not clear what you want to dismiss in your second view controller, so I will try to present the most likely scenarios:
If you want to dismiss the view controller presented modally (TagDetailControllerViewController), you need to dismiss it modally too.
This can be achieved by calling in your TagDetailControllerViewController itself:
[self dismissViewControllerAnimated:YES completion:nil];
Which works because, according to Apple's documentation:
If you call this method on the presented view controller itself, it automatically forwards the message to the presenting view controller.
Also, if you want to dismiss it directly from the view controller you used to present it, you can do it as follows:
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
Finally, if what you want is to dismiss a view that was pushed in your UINavigationController, then you can just pop it from the stack:
[self.navigationController popViewControllerAnimated:YES];
As you can see, the way a view is dismissed really depends on the way it was presented.
try this
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:NULL];

iOS - Display a UIViewController as fullscreen from within a UINavigationController

I need to present a UIViewController as fullscreen (Above all other views). This UIViewController is currently inside a UINavigationController.
Is it possible to have the UINavigationController present it's current top UIViewController modally?
From within the UIViewController I would like to fullscreen, if I use:
[self.navigationController presentViewController:self animated:YES completion:nil]
Nothing seems to happen.. Is there a reason this is not allowed?
EDIT
I have posted another question in which I have solved this issue for every scenario. (Code snippet included there)
Is it possible for a UIViewController to present itself?
If you want to present a view controller modally, you should be presenting it from a different view controller. The modal presentation will show the presented view controller over the navigation controller (in fullscreen)
For instance,
UIViewController *firstVC = self;
UIViewController *secondVC = <the VC you want to present>
[firstVC presentViewController:secondVC animated:YES completion:nil]
Or just use a modal segue in Interface Builder.
You should use this :
[self presentViewController:self.navigationController animated:YES completion:nil];
to show a controller.
Assuming that the view controller you want to show modally is the navigation controllers top view controller
[self presentViewController:self.navigationController.topviewcontroller animated:YES completion:nil];
Hope this helps

How to pop Navigation Controller iOS

I have 3 navigation controllers. Each with many view controllers.
1 NavigationController (modal Segue)-> 2 NavigationController (model Segue)-> 3 NavigationController
Now, how do you go from #3 NavigationController back to #1 NavigationController that I have been before? So I want
1 NavigationController (modal Segue)-> 2 NavigationController (model Segue)-> 3 NavigationController (HOW???)-> 1 NavigationController
(To clarify, I would not want to go to a new 1 NavigationController. I want to go to the one that I used before.)
Help!
[[self navigationController] popViewControllerAnimated:YES];
If you just want to dismiss the whole stack of 3 NavigationController, you can call this within any view controller in the 3
Objective C
[self.navigationController dismissViewControllerAnimated:YES completion:nil]
Swift 3, 4
self.navigationController?.dismiss(animated: true)
This will bring you back to the status before (model Segue)-> 3 NavigationController.
Maybe you can somehow call this in 2 before calling this in 3?
Use that:
[self.**presentingViewController** dismissViewControllerAnimated:YES completion:nil];
instead of:
[self dismissViewControllerAnimated:YES completion:nil];
In a view controller in navigationController1's stack, create an unwind #IBAction method:
Swift
#IBAction func unwindToMyViewController(_ segue: UIStoryboardSegue)
Objective-C
- (IBAction)unwindToMyViewController:(UIStoryboardSegue *)segue
In your storyboard, you can then hook up an unwind segue from a button in a view controller that is in the stack of navigationController3, by dragging from the button to the exit icon…
from there, select the unwind segue created above. When triggered, the segue will unwind ALL view controllers back to the view controller containing the unwind segue.
With help of this, You can get the 1 Nav controll :-
[(UINavigationController *)self.view.window.rootViewController popViewControllerAnimated:YES];
this code will pop a navigation controller with all view controllers in it
// pop root view controller
UIViewController *rootViewController = [self.navigationController viewControllers][0];
[rootViewController dismissViewControllerAnimated:YES completion:nil];
so you can do something like this:
// pop navigationController3 without animation
UIViewController *rootViewController3 = [navigationController3 viewControllers][0];
[rootViewController3 dismissViewControllerAnimated:NO completion:nil];
// pop navigationController2 with animation
UIViewController *rootViewController2 = [navigationController2 viewControllers][0];
[rootViewController2 dismissViewControllerAnimated:YES completion:nil];

Resources