Remove view controller from navigation stack after push segue (using Storyboard segues)

Multi tool use
Multi tool use
The name of the picture


Remove view controller from navigation stack after push segue (using Storyboard segues)



My app is contained in aUINavigationController. The root view controller A is essentially a login view, where the user will enter credentials and upon success will present the profile view controller B via a push segue. Right now the user gets the back button on the nav bar of B to navigate back to A. I want B to now be the root view controller on the navigation stack, effectively preventing the user from ever getting back to A until a new app launch.


UINavigationController



What is the correct way to handle this while still using a push segue? Should I perform the presentation of B without a segue and effectively start B off with a new navigation controller?





It would be better to make B the root view controller of the navigation controller. Present A modally (with no animation) from the viewDidAppear method of B, and it will be the first thing the user sees. When you dismiss it, it will be deallocated, and you'll be at B.
– rdelmar
Jan 20 '15 at 19:19







I agree with you 100%, however I have some specific specs I have to stick to which is why I'm attempting it this way. I do think your suggestion would be a simple way to approach this, so perhaps I'll give it a try and see if it would be preferred over the original specs.
– timgcarlson
Jan 20 '15 at 19:25




3 Answers
3



Just replace the rootViewController of your UIWindow.
controllerA and controllerB can be any Viewcontroller-Class you want.


UIWindow


Viewcontroller



You could use a simple UITableViewController for the Loginpage and then replace the rootViewController of your UIWindow with a UINavigationController holding controllerB


UITableViewController


UIWindow


UINavigationController


[UIView transitionFromView:controllerA.view
toView:controllerB.view
duration:0.65f
options:(UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionTransitionCrossDissolve)
completion:^(BOOL finished){
delegate.window.rootViewController = controllerB;
}];





This is the solution I ended up going with for now. Thanks for the answer!
– timgcarlson
Jan 20 '15 at 21:59



I know the question is slightly old, but having gone through this myself, I have finally found a solution which I think is better than the accepted answer.



Make the login controller the root controller of the navigation controller.



When login succeeds, remove the login controller from the navigation controllers viewcontrollers array and append your app's initial viewcontroller.


if let navigationController = navigationController {

var viewControllers = navigationController.viewControllers

for (index, viewController) in viewControllers.enumerated() where viewController is LoginViewController {
viewControllers.remove(at: index)
}

let storyBoard = UIStoryboard(name: "Main", bundle: Bundle.main)
let initialViewController = storyBoard.instantiateViewController(withIdentifier: "InitialViewController")

viewControllers.append(initialViewController)

navigationController.setViewControllers(viewControllers, animated: true)
}



The only other thing you have to do is add the following line to your initial viewcontroller's viewDidLoad:


navigationItem.hidesBackButton = true



The setViewControllers method with animated set to true takes care of the push animation you specified as a requirement.



EDIT:



I have made a method that can be added to the login controller, which not only works if you want the login controller to be shown as the first view controller in the app, but also if later authentication fails (expired credentials etc.) and you have shown the login controller modally:


func authenticationDidSucceed() {
// If the LoginController is in a navigation stack then
// replace it with the initial viewcontroller of the app
guard navigationController?.viewControllers.contains(self) ?? false else {
// Else it must be presented modally, so dismiss it
dismiss(animated: true, completion: nil)
return
}

guard let navigationController = navigationController else { return }

var viewControllers = navigationController.viewControllers

if let index = viewControllers.index(of: self) {
viewControllers.remove(at: index)
}

viewControllers.append(UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "InitialViewController"))

navigationController.setViewControllers(viewControllers, animated: true)
}



Just remember step 3 from above.



B should be contained in it's own navigation controller since A will no longer be accessible. You'll have to use something other than a push segue. transitionWithView works well:


transitionWithView


UINavigationController *newNavController;

[UIView transitionWithView:delegate.window
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^
{
[delegate.window addSubview:newNavController.view];
}
completion:^(BOOL finished)
{
delegate.window.rootViewController = newNavController;
}];

[delegate.window makeKeyAndVisible];






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

m5RFREhU,WefsFv,6t QB,xk,QeA91dYBlOVqx6
AIZ2ZZ5Om,jaKbpRKeYOen,HMr3oWXj,l wBpc3ITBXy1BZlr,JHho1JA3NfN0HVA2pE4x 4ooJoE

Popular posts from this blog

Keycloak server returning user_not_found error when user is already imported with LDAP

PHP parse/syntax errors; and how to solve them?

415 Unsupported Media Type while sending json file over REST Template