How can I calculate number of current VC's in Navigation stack? - ios

Any ideas? I want to know number of MyViewControllers.

use this
int count = [[navigationController viewControllers] count];
NSLog(#"controllers : %#", [navigationController viewControllers]);
NSLog(#"count : %d", count);
[navigationController viewControllers] which returns an array of controllers in navigation stack. using this array you can get the count of controllers.

You said "number of MyViewControllers" not number of viewControllers, so I assume you want to know how many of the viewControllers in the stack are instances of your own custom subclass. That's where the method [anyObject isKindOfClass] comes in. This snippet should help:
NSArray *viewControllerStack = [[self navigationController] viewControllers];
NSUInteger result = 0;
for(UIViewController *vc in viewControllerStack) {
if([vc isKindOfClass:[MyViewController class]] result++;
}
Is this what you're looking for?

Related

How to set segue doing pop to root and push a new one in storyboard?

I want to make a segue that makes navigation controller poptoroot and then make a new controller pushed into the navigation controller .
e.g Now the controller hierarchy is
navigationController->rootcontroller->controllerA ->controllerB
and i want to make a segue perfome in controller B,and the segue will make the hierarchy to
navigationController->rootcontroller-> controllerC
is this possible?
You want to set segue doing pop to root. This can be achieved using Unwind Segues. For more detail regarding this you can follow this Apple doc.
https://developer.apple.com/library/content/technotes/tn2298/_index.html#//apple_ref/doc/uid/DTS40013591-CH1-TNTAG2-ADDING_AN_UNWIND_SEGUE_TO_A_STORYBOARD
For pushing to new VC, You can simply push in storyboard.
You can use for loop to pop till root or where you want and use same method to push forward:
// For Pop
NSArray *viewControllers = [[self navigationController] viewControllers];
for( int i=0;i<[viewControllers count];i++){
id obj=[viewControllers objectAtIndex:i];
if([obj isKindOfClass:[ViewControllerYouWantToStopOn class]]){
[[self navigationController] popToViewController:obj animated:YES];
return;
}
}
//For Push
NSArray *viewControllers = [[self navigationController] viewControllers];
for( int i=0;i<[viewControllers count];i++){
id obj=[viewControllers objectAtIndex:i];
if([obj isKindOfClass:[ViewControllerYouWantToJumpOn class]]){
[[self navigationController] pushViewController:obj animated:YES];
return;
}
}
This code work for me :
self.performSegue(withIdentifier: "segue_id", sender: self)
var navigationArray = self.navigationController?.viewControllers
var i = navigationArray!.count - 2
while i > 0 {
navigationArray!.remove(at: i)
i = i - 1
}
self.navigationController?.viewControllers = navigationArray!

How can I pop to any view controller as I wish?

view controller A B C D
A -> B -> C-> D
popViewController only form D to C
popViewTopController only form D to A;
Any way can I pop to any view as I wish if I have 10 view controllers?
Thanks for everyone. will the popViewController pop to a new view Controller ?
Option 1: Select by class
To tell the navigationController to pop to a specific class, you can do as follows:
NSArray *allViewControllers = [self.navigationController viewControllers];
for (UIViewController *aViewController in allViewControllers)
{
if ([aViewController isKindOfClass:[B class]])
{
[self.navigationController popToViewController:aViewController animated:YES];
}
}
Take into account that you should only use this, if you are not pushing instances of the same class several times.
Option 2: Select by level
If you want to pop to a specific level, you can just select it by index at self.navigationController.viewControllers since it correspond to the levels. The first pushed UIViewController will be at index 0, the second at index 1 and so on:
NSArray *allViewControllers = [self.navigationController viewControllers];
UIViewController *aViewController = [allViewControllers objectAtIndex:level];
[self.navigationController popToViewController:aViewController animated:YES];
if you want to pop any view you want to change objectAtIndex:1,2,3..etc
it will pop to first,second etc... from the any views.
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
This is the method you are looking for (reference)
In Obj-c
- (NSArray *)popToViewController:(UIViewController *)viewController
animated:(BOOL)animated
You should pass in the view controller that you want pop to
Use the following UINavigationController method to go to any view controller on the current stack.
- (NSArray *)popToViewController:(UIViewController *)viewController
animated:(BOOL)animated
For example, if you are in a UIViewController and you want to pop back to the third one in the stack:
UINavigationController * nc = self.navigationController;
UIViewController * popToVC = [nc.viewControllers objectAtIndex:2];
[nc popToViewController:popToVC animated:YES];
SecondViewController *sec = [SecondViewController alloc] init];
[self.navigationController popViewController:Sec animated:YES];

inserting ViewController In between the stack of self.navigationController.viewcontroller

I have three viewcontollers in my navigation controller. Now what i want to do just insert a view controller in between the array of self.navigationController.viewControllers.
As I checked the property viewControllers is not a readonly property So i think we can set it also.
thats why I used the below code to insert my ViewController in between the stack.
But unfortunately it doesn't modify the stack of self.navigationController.viewControllers.
So how can I insert and modify the stack. Also be sure that I don't want to pushViewcontroller.
CXSTransactionSelectionViewController *trxSelectionVc = [self.storyboard instantiateViewControllerWithIdentifier:#"CXSTransactionSelectionViewController"];
NSMutableArray *viewControllers = [self.navigationController.viewControllers mutableCopy];
[viewControllers insertObject:trxSelectionVc atIndex:viewControllers.count-2 ];
[self.navigationController setViewControllers:viewControllers animated:YES];
NSLog(#"%#",self.navigationController.viewControllers);
Try to do something like this:
NSArray * oldViewControllers = [self.navigationController viewControllers];
NSArray * newViewControllers = [NSArray arrayWithObjects:[oldViewControllers objectAtIndex:0], newVC, [oldViewControllers objectAtIndex:1],nil];
[self.navigationController setViewControllers:newViewControllers];
using this my problem is resolved
CXSTransactionSelectionViewController *trxSelectionVc = [self.storyboard instantiateViewControllerWithIdentifier:#"CXSTransactionSelectionViewController"];
[self.navigationController.viewControllers insertObject:trxSelectionVc atIndex:1 ];
NSLog(#"%#",self.navigationController.viewControllers);

Best practice for pushing a viewController in UINavigationController stack

Sorry if this question was asked prior.
I wanted to know how do we handle navigationController stack like am looking for best practices
for now what i am doing is I check if a viewcontroller is already present and then in the navigation stack and then i pop it back by doing something like this
bool flag = NO;
for(LoginViewController *vc in self.navigationController.viewControllers)
{
if ([vc isKindOfClass:[LoginViewController class]]) {
flag = YES;
}
}
if (flag!=YES ){
LoginViewController *objVC = [[LoginViewController alloc]init];
[self.navigationController pushViewController:objVC animated:YES];
objVC = nil;
}else
{
[self.navigationController popViewControllerAnimated:YES];
}
Do i really need to check if any viewcontroller is already present in the navigation stack prior pushing it or does the navigation controller takes care of it and at sometime removes the viewcontroller which are not in use. Is there a better way to do this or am i already doing the right thing
In short how we can stop a viewcontroller from being pushed into the navigation stack twice.
popViewControllerAnimated will always pop the top most VC on the stack. It operates in LIFO fashion.
LoginViewController may not necessarily be the top most element on the stack hence in order to remove it you have to modify code this way.
LoginViewController *loginVC = nil;
NSUInteger index = [self.navigationController.viewControllers indexOfObjectPassingTest:^BOOL (id obj, NSUInteger idx, BOOL *stop) {
return [obj isKindOfClass:[LoginViewController class]];
}];
if (index != NSNotFound) {
//Found VC on stack
//Get LoginViewController instance
loginVC = [myArray objectAtIndex:index];
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
//Remove LoginViewController obj from stack
[viewControllers removeObjectIdenticalTo:loginVC];
//Reassign new array which does not contain LoginViewController
navigationController.viewControllers = viewControllers;
}
else {
//VC not found on stack
LoginViewController *objVC = [[LoginViewController alloc]init];
[self.navigationController pushViewController:objVC animated:YES];
}
Hope that helps!

How to "pop" several View controllers in UINavigationController Stack?

In my app I'm implementing UINavigationController. There are several UIViewControllers that are being pushed in the stack.
When I reach the last one, I wish to have (upon a user action) all the UIViewControllers be popped except for the first UIViewController. How do I do that?
I understand how to pop the last one, but how do I instruct all the previous ones to disappear as well?
You can try the popToRootViewControllerAnimated:, popToViewController:animated: and popViewControllerAnimated: messages of the UINavigationController class.
In your case it is really usefull to use popToRootViewcontrollerAnimated: as suggested by Irene, but if somebody need to pop exact number of controllers, then following code can be usefull:
- (void) popControllersNumber:(int)number
{
if (number <= 1)
[[self navigationController] popViewControllerAnimated:YES];
else
{
NSArray* controller = [[self navigationController] viewControllers];
int requiredIndex = [controller count] - number - 1;
if (requiredIndex < 0) requiredIndex = 0;
UIViewController* requireController = [[[self navigationController] viewControllers] objectAtIndex:requiredIndex];
[[self navigationController] popToViewController:requireController animated:YES];
}
}
Use
TravelViewController *travelView = [self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count-3];
[self.navigationController popToViewController:travelView animated:YES];

Resources