Pushing and removeFromParentControllers, Affected the structure of navigation controller - ios

enter image description here
Image on above link, cant include it in the post..
As I push from viewControllerA to B, then I push from B to C, then I use the following code to remove the viewControllerB and push C to B and remove viewControllerC:
NSMutableArray *navigationArray = [[NSMutableArray alloc] initWithArray: self.navigationController.viewControllers];
for(UIViewController *tempVC in navigationArray)
{
if([tempVC isKindOfClass:[viewControllerB class]])
{
[tempVC removeFromParentViewController];
}
}
[self performSegueWithIdentifier:#"toViewControllerB" sender:self];
for(UIViewController *tempVC in navigationArray)
{
if([tempVC isKindOfClass:[viewControllerC class]])
{
[tempVC removeFromParentViewController];
}
}
So now ViewControllerA is connected to the last ViewControllerB
After that I still get the back button in the navigation bar, but after I pressed the back button of it, the ViewControllerB popped back to ViewControllerA, but in the ViewControllerA, the navigation bar items and title are gone, I purposely push from C to B again to fix some memory issue, how can I make this work by taking out the two view controllers in the middle but not messing up the navigation controller? Is there any other alternatives to get this done? Thank you
I have another weird approach is to programatically create a navigation bar with the same items and title to cover it, but just seems so wrong...

First when you want to push from B to C and then remove B, you can try this
for(UIViewController *tempVC in navigationArray)
{
if([tempVC isKindOfClass:[viewControllerB class]])
{
[navigationArray removeObject:tempVC];
break;
}
}
[self.navigationController setViewControllers:navigationArray];
[self performSegueWithIdentifier:#"toViewControllerB" sender:self];
But you must ensure the segue is from C to B. Then you will get the Controllers A->C->B. If you want to push to ControllerC and remove Last C. Try to use the same function.

1) When you first push to your C controller from B then first Remove B controller
2) When you push to B controller from C controller then remove C controller.
// Code for removing C Controller from stack
NSArray *viewControllers = self.navigationController.viewControllers;
NSMutableArray *viewControllersMutable = [NSMutableArray arrayWithArray:viewControllers];
for (UIViewController *vc in viewControllers) {
if (([viewControllers indexOfObject:vc] != viewControllers.count - 1 ) && [vc isKindOfClass: C.class] ){
NSLog(#"removing contoller of kind C");
[viewControllersMutable removeObject:vc];
}
}
self.navigationController.viewControllers = viewControllersMutable.copy;
// Code for removing B controller
NSArray *viewControllers = self.navigationController.viewControllers;
NSMutableArray *viewControllersMutable = [NSMutableArray arrayWithArray:viewControllers];
for (UIViewController *vc in viewControllers) {
if (([viewControllers indexOfObject:vc] != viewControllers.count - 1 ) && [vc isKindOfClass: B.class] ){
NSLog(#"removing contoller of kind B");
[viewControllersMutable removeObject:vc];
}
}
self.navigationController.viewControllers = viewControllersMutable.copy;
Note -> You can do this in a same code Only "OR" condition is checked, means the controller is B or C.

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!

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

How to control the back button navigation in iPad (UISplitViewController)ios xcode

I have used the following code for deleting my login page from the navigationcontroller(viewcontrollers) so that it will not come into the view again when going back (back button).
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
NSMutableArray *VCs = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
if([[VCs objectAtIndex:[VCs count] - 2] isKindOfClass:[loginViewController class]]&&(VCs.count>=4))
{
[VCs removeObjectAtIndex:[VCs count] - 2];
[VCs removeObjectAtIndex:[VCs count] - 2];
[self.navigationController setViewControllers: VCs];
}
}
This works perfectly for iPhone. But for iPad, since we are using splitViewController, if we code like
NSMutableArray *VCs = [NSMutableArray arrayWithArray:self.splitViewController.viewControllers];
What we will be getting is an array of navigationControllers. Is there a genuine logic by which we can delete a particular viewcontroller from the splitviewcontroller?
Your split view controller, as you said, will return an array of nav controllers (depending on the project setup). Once you have a reference to those, you can manipulate them however you want.
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *masterNavVC = (UINavigationController *)splitViewController.viewControllers.firstObject;
UINavigationController *detailNavVC = (UINavigationController *)splitViewController.viewControllers.lastObject;
//Now you have the master and detail navigation controllers, get your VC you need to manipulate
NSMutableArray *masterVCs = masterNavVC.viewControllers;
NSMutableArray *detailVCs = detailNavVC.viewControllers;
//Remove the ones you need to - this example is arbitrary. Put your logic here
if(masterVCs.count > 0 && [masterVCs[0] isKindOfClass:[LoginViewController class]])
{
//Remove or add
}

Removing ViewController from navigation stack

I do it with code:
NSArray *viewControllersFromStack = [self.navigationController viewControllers];
NSMutableArray *viewControllersFromStackMutable = [NSMutableArray arrayWithArray:viewControllersFromStack];
NSMutableArray *viewControllersToRemove = [[NSMutableArray alloc]init];
for (UIViewController *currentVC in viewControllersFromStack)
{
if ([currentVC isKindOfClass:[TalksViewController class]])
{
[viewControllersToRemove addObject:currentVC];
if (viewControllersToRemove.count == 2)
{
UIViewController *oneVCtoRemove = [viewControllersToRemove objectAtIndex:0];
[viewControllersFromStackMutable removeObject:oneVCtoRemove];
[self.navigationController setViewControllers:viewControllersFromStackMutable];
}
}
}
Problem is that I have reference to removed VC's in navigation Item. How to fix it?
When you want to remove a view from the navigation stack you can simply just call this method on the navigation bar to pop the view from the stack:
[self.navigationController popViewControllerAnimated:YES];
To pop an external view use
for(UIViewController *currentVC in viewControllersFromStack)
{
if([currentVC isKindOfClass:[TalksViewController class]])
{
[currentVC.navigationController popViewControllerAnimated:YES];
}
}
The above answer is correct.
I have 'A' as rootview controller. 'B to F' are other view controllers. From 'F', if I wanted to go directly to 'A', it is as under.
[self.navigationController popToRootViewControllerAnimated:YES];
BUT if I wanted to jump to 'B' then the code in answer is helpful. I only changed the array of view controllers to run reverse with 'reverseObjectEnumerator' and Animated to NO with 'popViewControllerAnimated:NO'. the Code is as under
NSArray *viewControllersFromStack = [self.navigationController viewControllers];
for(UIViewController *currentVC in [viewControllersFromStack reverseObjectEnumerator])
{
if(![currentVC isKindOfClass:[A class]] && ![currentVC isKindOfClass:[B class]])
{
[currentVC.navigationController popViewControllerAnimated:NO];
}
}

Resources