Pushing View Controller more than once is not supported? - ios

I am getting the following error whenever I try to switch views like this:
-(void)changeView1ToView4 {
[self.navigationController1 pushViewController:view4 animated:YES];
}
This doesn't happen when the app first loads and user goes directly to this view. This crash only happens when I go to one of my other views, come back to the main menu, and then try to go to this view.
Also if you weren't sure already, I am using a UINavigationController. Also this code is in the app delegate and I am calling it from a view controller which has a parent view so I am using a .reference to call it like this:
[self.reference changeView1ToView4];
Is there any real way to fix this?
Thanks!
Edit1:
[self.navigationController1 pushViewController:view4 animated:NO];
[self.navigationController1 pushViewController:view4 animated:YES];
I tried that and got this crash message in the console:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Pushing the same view controller instance more than once is not supported (<View2: 0x18d540>)'

When pushing 2 views onto the stack, try to call:
[self.navigationController1 pushViewController:view4 animated:YES];
and
[self.navigationController1 pushViewController://secondviewcontrollername// animated:NO];
If you try to push more than one view with the animated: field set to YES on both, then you confuse the stack. Only animate one view at a time.

just an FYI, if you call setViewControllers:animated: there's no need to call pushViewController: afterwards, else you'll get the "Pushing the same view controller instance more than once is not supported" crash.

#try {
[self.navController pushViewController:viewController animated:NO];
} #catch (NSException * e) {
NSLog(#"Exception: %#", e);
[self.navigationController popToViewController:viewController animated:NO];
} #finally {
//NSLog(#"finally");
}

Check this condition before push
if (![[self.navigationController topViewController] isKindOfClass:[YOURCONTROLLER class]])
[self.navigationController pushViewController:YOURCONTROLLER animated:YES];

Related

pushViewController in viewWillAppear failed after popToRootViewController

there have 3 view controllers, A,B,C, all designed in storyboard.
in all pushViewController: controllers were got from [self.navigationController instantiateViewControllerWithIdentifier:#"A/B/C_Controller"];
In A_ViewController ( root controller ):
-(void)viewWillAppear
{
[self.navigationController pushViewController:B_Controller animated:YES];
}
In B_ViewController:
-(IBAction)someButtonClick
{
[self.navigationController pushViewController:C_Controller animated:YES];
}
In C_ViewController:
-(IBAction)someButtonClick
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
Problem:
A_viewController -> B_viewController -> C_viewController is fine.
but after popToRootViewController to A From C, A can't push to B anymore.
and other pushViewController: all can't works, popViewControllerAnimated: also cause crash.
Note.
have tried
// in A view
dispatch_async(dispatch_get_main_queue(),^{
[self.navigationController pushViewController:B_viewController animated:YES];
})
in this post, but it doesn't works for me.
does anyone know what happens in view controller stacks?
have struggling in this issue all day, any help will be appreciated!
When you When you popToViewController from C, the viewWillAppear method will in A be called just before the animation. Now, at this point, since the transition is in progress, you might get some kind of warning in the debugger like:
"Warning: Attempting to push .... while a transition is in progress"
You need to call the navigation controller methods in such a way that they do not overlap each other.
Calling pushViewController in the viewDidAppear method of A would be better in this context.

why I can't pop the last view in the navigation stack?

I want to pop the last view in my app, so I'm calling this function:
[self.navigationController popViewControllerAnimated:YES];
and self is the last view controller, I expect that the app will exit, but that does't happen why ?
For going to the rootView u need to call as below,
[self.navigationController popToRootViewControllerAnimated:YES]; // Returns the root/last vie controller.
and the one u used is below,
[self.navigationController popViewControllerAnimated:YES]; // Returns the popped controller.
If you wish to exit your app, just do that:
[[NSThread mainThread] exit]
Anyway, your way:
[self.navigationController popViewControllerAnimated:YES];
It's common in android, not in iOS.

Push back insted of popto showing error

#try {
NSArray *viewContrlls=[[self navigationController] viewControllers];
NSUInteger totalelement = [viewContrlls count];
UIViewController *LastElementController = [viewContrlls objectAtIndex:totalelement-2];
[self GotoDifferentViewWithAnimation:LastElementController];
} #catch (NSException * e) {
NSLog(#"Exception: %#", e);
}
I am trying to get the last visited viewcontroller and pushback there with animation using the above code. It's showing the last visited viewcontroller properly like,
LastElementController --- <RRLoginViewController: 0x10b324e60>
But getting complietime err,
Pushing the same view controller instance more than once is not supported (<RRLoginViewController: 0x10b324e60>)
any help.....
You're trying to push a view controller that's already in the navigation stack. Hence, you cannot "go back" to the view controller via "pushing it again".
[self.navigationController popToViewController:LastElementController animated:YES];
will do the job, but I think you want to save the condition of that View Controller.

iOS, how should go back up the navigation stack but not to root?

I'm using a storyboard and storyboard id's, I'm several controllers deep in the navigation stack.
Menu Controller
Selection Controller
Item Controller
Result Controller
I'm currently on the 'Result Controller' and I want go to the 'Item Controller', but reset / reload that controller, I would be passing in the same property values that it currently has. So in effect I would be going up two levels then push.
I just wondered whats the best way to achieve this?
I guess I could call pop a couple of times then push within my 'Result Controller' passing property values to the 'Item Controller'?
Hmm, I guess I would have keep the animation for the first pop then disable it for the two pushes.
Hope this makes sense.
Try this. Maybe it will help you.
NSArray *vList = [[self navigationController] viewControllers];
UIViewController *view;
for (int i=[vList count]-1; i>=0; --i) {
view = [vList objectAtIndex:i];
if ([view.nibName isEqualToString: #"ItemController"])
{
[self.navigationController popToViewController:view animated:YES];
break;
}
}
for (UIViewController *controller in [self.navigationController viewControllers])
{
if ([controller isKindOfClass:[YourViewCOntrollerName class]])
{
[self.navigationController popToViewController:controller animated:YES];
break;
}
}
Try this
[self.navigationController popToViewController:[[self.navigationController viewControllers] objectAtIndex:2] animated:YES];
you can go back at any index you want
Pop to specific view controller( in this case ItemController) you can use below code
[self.navigationController popToViewController:ItemController animated:YES];
The way you try to make it is not really optimal, and could end up causing you problems. The clean way to do this would be to code a way to reset the "Item Controller" so you just have to do 1 pop.

popToViewController is not working "Tried to pop to a view controller that doesn't exist"

I am trying to use popToViewController and it I keep getting the error "Tried to pop to a view controller that doesn't exist"?
I am in a Settings view and when the user clicks "Sign Out" I dismiss the Settings VC and segue back to the mainView where an unwind segue method is called. In the unwind segue method I call the following.
-(IBAction)endSettingsViaLogout:(UIStoryboardSegue *)segue {
//[self performSegueWithIdentifier:#"mainToLoginSegue" sender:self];
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
//[self.navigationController popViewControllerAnimated:YES];
DLog(#"User finished with search");
}
When the poptoVC is called I get the "Tried to pop to a view controller that doesn't exist".
I NSLog the self.navigationController.viewControllers and I can see the stack of VC's and the one I want to pop to is in there?
/// UPDATE //////
Ok here is what I have found. If my segue to Settings is a regular "push" segue then the code works and I get popped back to where I want. If I do a custom segue, having come from the left side of the screen then it stops working. Even with the custom segue the self.navigationcontroller.viewcontrollers shows its in the stack. So why can't I pop back to it? Or how can I pop back to it with the custom segue?
Do I get the view controller hierarchy right?
On your basis UINavigationViewController you have set a main view controller as root view controller.
Then a settings view controller has been pushed upon this.
Via "Sign out" the settings view controller is being segued back to the main view controller.
If so, you are actually trying pop "back" to a view controller, that does not exist, since you already have reached the root view controller of your navigation controller stack. In this case, all previously initialized controllers have been popped from the stack and you would have to reinitialize and push the desired view controller.
If I am missing some important point, it would be helpful, if you would describe your actual view controller stack at the moment the "Sign out" option is available. Furthermore, what exactly is printed on the console if you log the self.navigationController.viewControllers array?
well that basically tells objectatindex 1 does not exist:
things to try:
objectatindex:0
or
nslog(#"%d",[[self.navigationController.viewControllers]count]);//add it before the popline and see if it works
if its the topview controller then try below:
[navigationController topViewController] instead
NSArray *viewControllers = [[self navigationController] viewControllers];
for( int i=0;i<[viewControllers count];i++)
{
id obj=[viewControllers objectAtIndex:[viewControllers count]-i-1];
if([obj isKindOfClass:[OrderCheckOutViewController class]]){
[[self navigationController] popToViewController:obj animated:YES];
return;
}
}
you can use the snippet to pop out to targetVC's next viewController in the navigationController's stack.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
BOOL findIt = NO;
UIViewController *targetVC = nil;
for (UIViewController *subVC in self.navigationController.viewControllers) {
if (findIt) {
break;
}
if (subVC == xxx) {
findIt = YES;
}else{
targetVC = subVC;
}
}
[self.navigationController popToViewController:targetVC animated:NO];
});

Resources