Find ViewController in NavigationController with special key - ios

I have a NavigationController with different ViewControllers. Sometimes I want to push a ViewController to NavigationController, which is already included.
In this case I want to move to the existing from TopController, and pop all other ViewControllers between top and the existing one.
Is there a way to give a ViewController a special id (for example a NSString), to find him later in "NavigationController.viewControllers"?
Or should I use a seperate Dictionary to manage my ViewControllers?
Or is there a better way, I dont consider.
best regards

On your appDelegate, you can store all your ViewController and when you want to pop call :
[self.navigationController popToViewController:yourViewController animated:YES];
Or you can try to search
NSArray *viewControllers = self.navigationController.viewControllers
for (UIVIewController *anVC in viewControllers) {
if (anVC isKindOfClass:[yourController class] {
[self.navigationController popToViewController:anVC animated:YES];
break;
}
}
Hope it will help you.

Note : As the view controllers are the same class, most times
Add strUniqueID property on each controller while pushing view controller to navigation controller don't forget to set it
Now you know which unique ID's you want remove, so find it
//Firstly find your viewController
for(id viewcontroller in self.navigationController.viewControllers)
{
//For finding specific viewController use isKindOfClass
if(viewcontroller isKindOfClass:[YourViewControllerNameHere Class])
{
//Now find UniqueIDHere
YourViewController *objYourViewController = (YourViewController *)viewcontroller
if(YourViewControllerNameHere.strUniqueID isEqualToString:removeUniqueIDHere])
{
//Now pop to YourViewController
[self.navigationController popToViewController:viewcontroller animated:YES];
break;
}
}
else if(viewcontroller isKindOfClass:[YourDifferentViewControllerNameHere Class]) //Different ViewControllers here like this
{
//Now find UniqueIDHere
YourDifferentViewController *objYourDifferentViewController = (YourViewController *)viewcontroller
if(YourDifferentViewController.strUniqueID isEqualToString:removeUniqueIDHere])
{
//Now pop to YourViewController
[self.navigationController popToViewController:viewcontroller animated:YES];
break;
}
}
}
Try this :
//Firstly find your viewController
for(id viewcontroller in self.navigationController.viewControllers)
{
//For finding specific viewController use isKindOfClass
if(viewcontroller isKindOfClass:[YourViewControllerNameHere Class])
{
//Now pop to YourViewController
[self.navigationController popToViewController:viewcontroller animated:YES];
break;
}
}

Swift 5
let vc = navVC.viewControllers.first(where: { $0.hasKey })

Related

Navigation Back shows other Viewcontroller during the transition

I have three Viewcontrollers : ViewControllerA, ViewControllerB and ViewControllerC.
When I am in ViewControllerC, I click on Navigation Back button to go back to ViewControllerA directly, skipping ViewControllerB.
I have tried following approaches, both of them work. But, I wonder while transiting from ViewController C to ViewController A, it shows ViewController B in one second for during the transition.
Is there a way just directly navigate from ViewController C to ViewController A skipping ViewControllerB.
Approach 1:
-(void) viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
NSLog(#"back button pressed");
[self.navigationController popViewControllerAnimated:YES];
}
[super viewWillDisappear:animated];
}
Approach 2:
-(void) viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
NSLog(#"back button pressed");
//[self.navigationController popViewControllerAnimated:YES];
NSMutableArray *allViewControllers = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
for (UIViewController *aViewController in allViewControllers) {
if ([aViewController isKindOfClass:[ViewControllerA class]]) {
[self.navigationController popToViewController:aViewController animated:NO];
}
}
}
[super viewWillDisappear:animated];
}
You need to use setViewControllers method, and pass only the viewControllerA that is the first element in your navigationController.viewControllers array
Code
- (IBAction)backAction:(id)sender {
UIViewController * viewControllerA = [self.navigationController.viewControllers firstObject]; //we get the first viewController here
[self.navigationController setViewControllers:#[viewControllerA] animated:YES];
}
similar answer here How to start from a non-initial NavigationController scene but in swift
Try popToRootViewControllerAnimated . It will move to First ViewController which NavigationController embed.
[self.navigationController popToRootViewControllerAnimated:YES];
NSArray *arrayViewControllers = [self.navigationController viewControllers];
for (UIViewController *viewcontroller in arrayViewControllers) {
if ([viewcontroller isKindOfClass:[ViewControllerA class]]) {
[self.navigationController popToViewController:viewcontroller animated:true];
}
}

iOS - a questions about present and push the controllers

There are five controllers here, AViewController, BViewController, CViewController,DViewController,EViewController,controllers here,
A present---> B
B present---> C
C push--->D
D push--->E
Now, if I want to go back from EViewController to AViewController in one step, what code should I write?
[self.navigationController popToRootViewControllerAnimated:animated];
1) Getting the desirable ViewController as Below
for (id controller in [self.navigationController viewControllers])
{
if ([controller isKindOfClass:[AViewController class]])
{
[self.navigationController popToViewController:controller animated:YES];
break;
}
}
2) Here you have A,B,C,D,E Controllers. means A would be on 1 Position so what can you do
you can hard wired the Index as Below
[self.navigationController popToViewController:[[self.navigationController viewControllers] objectAtIndex:0] animated:YES];
3) Pop to the first viewController or rootViewController
[self.navigationController popToRootViewControllerAnimated:animated];
Use unwind segues.
In AViewController add bellow code
-(IBAction)prepareForUnwind:(UIStoryboardSegue *)segue {
}
Go to User Interface of EViewController and Ctrl-drag from the button (you want set action) to the “Exit” outlet, you will see a modal popup.
You can do it recursively with generic solution. First of all you should have reference to A's navigation controller and then you should write recursive method to get active navigation controller like :`
-(UINavigationController*)getActiveNavigationController : (UINavigationController*)navigationController {
if ([navigationController.presentedViewController isKindOfClass:[AViewController class]]) {
return [self getActiveNavigationController:(UINavigationController*)((AViewController*)navigationController.presentedViewController)
];
}
if ((UINavigationController*)navigationController.presentedViewController == nil) {
return navigationController;
}
return [self getActiveNavigationController:(UINavigationController*)navigationController.presentedViewController];
}
`
After that you should write method like
-(void)getInitialScreen:(UINavigationController*)AViewControllerNavigationController {
if ([AViewControllerNavigationController.presentedViewController isKindOfClass:[AViewController class]]) {
return;
}
UINavigationController *navigation = [self getActiveNavigationController:AViewControllerNavigationController];
[navigation dismissViewControllerAnimated:YES completion:^{
[self getInitialScreen:AViewControllerNavigationController];
}];
}
finally after you wrote those 2 methods. You can call them like below and you can always get AViewController
[self getInitialScreen:AViewControlelrnavigationcontroller];
[AViewControlelrnavigationcontroller popToRootViewControllerAnimated:YES];

How t go at specific page in ios

I know this question have been answered before, but i have difficulty to pop on specific page in ios. As i have already tried many times. as i have build 4 pages and and want to move last page to second page.
with the help of this code i have gone through first page
[self.navigationController popToRootViewControllerAnimated:YES];
and with the help of this page i have gone to 3rd page.
[self.navigationController popViewControllerAnimated:YES];
but for second page i have written this code
but it's not working
ViewPage2 *ptwo=[[ViewPage2 alloc] initWithNibName:#"ViewPage2" bundle:nil];
[self.navigationController popToViewController:ptwo animated:YES];
It is because you create new view controller which is not in the stack. What you should do is following:
for (UIViewController *vc in self.navigationController.viewControllers) {
if ( [vc isKindOfClass:ViewPage2]){
[self.navigationController popToViewController:vc animated:true];
return; //optional
}
}
ViewPage2 *ptwo;
for (UIViewController *vc in self.navigationController.viewControllers) {
if ([vc isKindOfClass:[ViewPage2 class]]) {
ptwo = (ViewPage2 *)vc;
break;
}
}
[self.navigationController popToViewController:ptwo animated:true];
Here is the simple answer:
NSArray *arr = [self.navigationController viewControllers];
[self.navigationController popToViewController:[arr objectAtIndex:0] animated:YES];
In place of,
[arr objectAtIndex:0]
here you can give index of specified view controller that you need to pop.
You can try doing this
first import the ViewController on which page u want to go.
like
#import ViewController.h
Then u can do the following
instantiate the class
ViewController *controller = [[ViewController alloc ] init];
[self.navigationController pushViewController:controller animated:YES];
or you can do popToViewController too
for (UIViewController *controller in self.navigationController.viewControllers) {
//Do not forget to import YourViewController.h
if ([controller isKindOfClass:[ViewController class]]) {
[self.navigationController popToViewController:controller
animated:YES];
break;
}
}

how to move between segues in navigation controller?

In my story board I have:
NavController-> View1(root) -> View2 ->View3 ->View4
I can normally use the flow in that order and navigation between segues is easy.
But How to go from View1 to View4 .. and from View4 there is back button should take you to View3?
Because if I made direct Segue From View1 to View4 ,, I cant reach View3.
Please let me know how to do this. Thanks in advance.
Here is an example with 3 viewcontrollers only but it will be the same logic:
You need to create segue between viewcontrollers like this:
viewController1 --- segueFrom1To2 ----- viewController2
viewController1 --- segueFrom1To3 ----- viewController3
viewController2 --- segueFrom2To3 ----- viewController3
Then you need a property in your viewController2, let's say: goToNextVc;
So, in your viewController1, you will be able to set this property when your perform the appropriate segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
ViewController2 *vc2 = segue.destinationViewController;
if ([segue.identifier isEqualToString:#"segueFrom1To3"])
{
vc2.goToNextVc = YES;
}
else{
vc2.goToNextVc = NO;
}
}
And now in the viewWillAppear of viewController2, simply add:
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
if (self.goToNextVc){
self.goToNextVc = NO;
[self performSegueWithIdentifier:#"segueFrom2To3" sender:self];
}
}
If you don't want to see the transition between viewController1 and viewController2, simply create a custom segue, let's say SegueNoTransition in which you need to override perform:
-(void) perform{
[[[self sourceViewController] navigationController] pushViewController:[self destinationViewController] animated:NO];
}
And replace the type "show" of segueFrom1To3 with "custom" and the class with SegueNoTransition;
for (UIViewController *controller in self.navigationController.viewControllers) {
if ([controller isKindOfClass:[yourViewController class]]) {
[self.navigationController popToViewController:controller
animated:YES];
}
else {
NSLog(#"Not Found");
}
}
// You must import the viewController where you want to move.
// yourViewController = viewController where you want to go in example.

Popping to a specific viewcontroller in a navigation stack

I have a come across a piece of code to pop to a specific viewcontroller in a navigation stack as below
for (UIViewController* viewController in self.navigationController.viewControllers) {
if ([viewController isKindOfClass:[MyGroupViewController class]] ) {
MyGroupViewController *groupViewController = (MyGroupViewController*)viewController;
[self.navigationController popToViewController:groupViewController animated:YES];
}
}
The objective is to pop to MyGroupViewController. But I am not understanding this line of code.
MyGroupViewController *groupViewController = (MyGroupViewController*)viewController;
Whats exactly happening here. I don't think a new instance of MyGroupViewController is being created here.
//This for loop iterates through all the view controllers in navigation stack.
for (UIViewController* viewController in self.navigationController.viewControllers) {
//This if condition checks whether the viewController's class is MyGroupViewController
// if true that means its the MyGroupViewController (which has been pushed at some point)
if ([viewController isKindOfClass:[MyGroupViewController class]] ) {
// Here viewController is a reference of UIViewController base class of MyGroupViewController
// but viewController holds MyGroupViewController object so we can type cast it here
MyGroupViewController *groupViewController = (MyGroupViewController*)viewController;
[self.navigationController popToViewController:groupViewController animated:YES];
}
}
Also you can do like this
if ([viewController isKindOfClass:[MyGroupViewController class]] ) {
[self.navigationController popToViewController:viewController animated:YES];
}
Swift code
//Itrate through all the view controllers in navigation stack
for vc in self.navigationController!.viewControllers {
// Check if the view controller is of MyGroupViewController type
if let myGropupVC = vc as? MyGroupViewController {
self.navigationController?.popToViewController(myGropupVC, animated: true)
}
}
The view controllers of a navigation controller stack are being enumerated. Since these view controllers can be of any kind (but will always inherit from UIViewController), the generic UIViewController is used. However, the compiler will not know what type that view controller is, so it is being casted to a MyGroupViewController. When that happens, the compiler knows what the type of class and you can send it messages that only apply to that class.
In this case it is kind of unnecessary, as it could be simplified to this:
(UIViewController* viewController in self.navigationController.viewControllers) {
if ([viewController isKindOfClass:[MyGroupViewController class]] ) {
[self.navigationController popToViewController:viewController animated:YES];
}
}
Short answer: it changes a variable type to the type specified in the parentheses to avoid compiler warnings.
for (int m=0; m<[self.navigationController.viewControllers count]; m++) {
if([[self.navigationController.viewControllers objectAtIndex:m] isKindOfClass:[MyGroupViewController class]]) {
MyGroupViewController * groupViewController = [self.navigationController.viewControllers objectAtIndex:m];
[self.navigationController popToViewController:groupViewController animated:YES];
}
}
- (void) RetunToSpecificViewController{
for (UIViewController *controller in self.navigationController.viewControllers) {
if ([controller isKindOfClass:[AnOldViewController class]]) {
//Do not forget to import AnOldViewController.h
[self.navigationController popToViewController:controller
animated:YES];
break;
}
}
On Swift
func RetunToSpecificViewController()
{
let viewControllers: [UIViewController] = self.navigationController!.viewControllers as [UIViewController]
self.navigationController!.popToViewController(viewControllers[viewControllers.count
- 5], animated: true)
}
We have write a better tutorial on that , You can check
https://appengineer.in/2014/03/13/pop-to-specific-view-controller-in-ios/

Resources