I have an app that has two storyboards: One for onboarding which displays a PageViewController with info about the app and the main view which shows displays a webview of the actual content.
I am trying to build in a sing out function to remove the data and bring them back to the Onboarding screen from where they will authenticate again. I have tried the following code after signing out but am not getting results.
let storyBoard: UIStoryboard = UIStoryboard(name: "Onboarding", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "PageControlViewController")
self.navigationController?.pushViewController(newViewController, animated: true);
This code does nothing and the app continues as normal. Replacing the pushViewController() with present() does work but by showing a modal over the existing view.
self.present(newViewController, animated: true, completion: nil)
My intention is to completely destroy the Main view and let the Onboarding view initiate a new version of the Main view.
As your code rightly shows, .pushViewController is meaningful only if self.navigationController is not nil. But in your case, self.navigationController is nil — your view controller is not in a navigation interface. Hence pushing is impossible and nothing happens.
Related
I have an app that I need to display a pin code screen every time the app is opened. I'm successfully displaying the modal view, but it doesn't cover the navigation bar at the top, and it doesn't cover the tab bar at the bottom. I believe it's because of how I'm presenting it, but I'm not seeing a way to change it.
This is how I'm presenting the controller
let newVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginView")
let view = window?.rootViewController as! UITabBarController
view.selectedViewController?.show(newVC, sender: nil)
This is the storyboard to give you an idea of the app.
The problem is your use of UIViewController's api, show. The function is overridden by UINavigationController in this case and push will be used to present the view controller. If your plan is to modally present a view controller, rather use present
selectedViewController?.present(newVC, animated: true, completion: nil)
We are looking to change the way a user logs out of our app. In order to do that, we want to dismiss all the VCs below the current VC and put another VC on top as the root VC. Right now we are doing this which I believe does not dismiss any VC below from memory.
let viewController = storyboard?.instantiateViewController(withIdentifier: "SignIn")
if let unwrappedViewController = viewController {
self.present(unwrappedViewController, animated: true, completion: {})
}
The problem is that the VC that we want to put on top is not embedded in a Navigation Controller or tab bar controller. How would we dismiss the VCs and set the new VC as the main VC as if the user was opening the app for the first time without having previously logged in? We also do want the transition to be animated with whatever animation is normal for that event (modal animation is fine). I have read a bunch of different ways on doing it but I want to know which way is best practice and should be implemented specifically dismissing all VCs and putting a new VC that isn't in a Nav controller on top.
If you can access the UIWindow of the app, you can set its rootViewController property to your sign-in view controller, effectively removing all current view controllers and adding the sign-in view controller instead. Here's an example:
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
// Should remove all subsequent view controllers from memory.
appDelegate.window?.rootViewController.dismiss(animated: true, completion: nil)
// Set the root view controller to a new instance of the sign in view controller.
appDelegate.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SignIn")
In my App, I've created a new storyboard that serves as a very basic tutorial for how to use certain features. (Instructions.storyboard). This storyboard has it's own class - InstructionsVC.swift
I want to present InstructionsVC when MainVC loads within viewDidAppear.
It works great. Fires up on App load just like it's supposed to. The problem occurs when I press the [Close] button on the Instructions interface. It closes the VC, fades to the main screen, and then immediately fires the Instructions VC back up.
How can I prevent the Instructions VC from loading back up once it's closed?
func openInstructions() {
let storyboard = UIStoryboard(name: "Instructions", bundle: nil)
let instructionsView = storyboard.instantiateViewController(withIdentifier: "instructionsStoryboardID")
instructionsView.modalPresentationStyle = .fullScreen
instructionsView.modalTransitionStyle = .crossDissolve
self.present(instructionsView, animated: true, completion:nil)
}
override func viewDidAppear(_ animated: Bool) {
openInstructions()
}
And within my instructions class, I have the following action on the close button:
#IBAction func closeButtonPressed(_ sender: UIButton) {
let presentingViewController: UIViewController! = self.presentingViewController
presentingViewController.dismiss(animated: true, completion: nil)
}
Note - I'd rather not use UserDefaults to resolve this, because I'm going to be incorporating something similar in other parts of the App and don't want to resort to UserDefaults to achieve the desirable behavior.
Thanks in advance buddies!
viewWillAppear and viewDidAppear are called every time a view controller's content view becomes visible. That includes the first time it's rendered and when it's shown again after being covered by a modal or by another view controller being pushed on top of it in a navigation stack.
viewDidLoad is only called once when a view controller's content view has been loaded, but before it is displayed. Thus when viewDidLoad is called it may be too soon to invoke your second view controller.
You might want to add an instance variable hasBeenDisplayed to your view controller. In viewDidAppear, check hasBeenDisplayed. If it's false, display your second view controller and set hasBeenDisplayed to true.
this question may asked before but i can't find any related question thats why posting a new one
so i have 3 tabs and in tab3 i have user profile Tab
in tab3 i wanna show loginViewController (if user haven't logged in yet) else i want to show the default profile tab
i can pass a segue using performSegue or present a view controller like this :
let loginPageView = self.storyboard?.instantiateViewController(withIdentifier: "LoginVC") as! SignupViewController
self.present(loginPageView, animated: true, completion: nil)
but i dont want that ,
i wanna show a different VC at the place of Default VC if user haven't logged in yet without any animation or transition
e.g.
producthunt's iOS app
if user's didn't logged in
and if he did logged in:
see the first image they are not presenting it as pop over or modal.
it seems like they do it on a same VIewController but i'm not sure. anybody can guide me here ?
replacing current Viewcontroller with desired ViewController did the job
let loginPageView = self.storyboard?.instantiateViewController(withIdentifier: "LoginVC") as! SignupViewController
var VCs = self.navigationController?.viewControllers
VCs?.removeLast() // here i removed the current VC
VCs?.append(loginPageView) after that added the desired VC
self.navigationController?.setViewControllers(VCs!, animated: false) // here i'm setting the viewcontrollers with any animation.
I am breaking up my project into multiple storyboards. I have a login storyboard with a navigation controller. The last step "Complete Registration" takes you to main.storyboard.
This leaves the navigation controller in place, and the back button takes you back to register. I obviously don't want that. I know I can hide the bar by using:
self.navigationController?.navigationBarHidden = true
But how can I leave the navigation controller?
Any help would be greatly appreciated!
The easiest and most correct way to do this would be to make your login screen a modal view. If you don't want to give your user the ability to go back, then you shouldn't use a push segue. You should use a modal view.
In the iOS Human Interface guidelines it says that modal views should be used for "a self-contained task [that] must be completed—or explicitly abandoned—to avoid leaving the user’s data in an ambiguous state."
A modal view will make it so your login and your main screen have to be in separate Navigation Controllers.
In the completion handler of the "Complete Registration" action you'll want to use the following code.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateInitialViewController() as! (TypeOfViewController)
self.presentViewController(viewController, animated: true, completion: nil)
If your main.storyboard is already embedded in a NavigationController (Initial view controller is a UINavigationController) then you'll have to do that a little bit differently.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateInitialViewController()
self.presentViewController(viewController, animated: true, completion: nil)