Going directly to Main View controller for already logged in user - ios

I have a loginViewController as my rootviewcontroller followed by the main screen and then other screens. My views follow push and pop approach. What I want is, if a user is already logged in my view should start from main screen else start from login screen, and if I logout from main screen it should go back to login screen and the push and pop structure should be maintained. I can achieve this using the modal transition, but I need to use push and pop approach, is this possible? Currently I have checked a already logged in condition in my appdelegate to set the rootview controller but it fails if I attempt to log out as its not present in my navigation controller stack.
if !alreadyLoggedin
{
let mainListVC = storyBoard.instantiateViewControllerWithIdentifier(“MainListViewController”)
self.window!.rootViewController = mainListVC
}
else
{
let loginVC = storyBoard.instantiateViewControllerWithIdentifier("ViewController")
self.window!.rootViewController = loginVC
}

It's basic use case, Please follow my steps.
In your story create navigation view controller with view controller.
Select navigation view controller as your initial view controller in storyboard.
Create three views controllers- InitialViewController, LoginViewController and MainViewController and set storyboard id for all view controllers.
Created sample project for you. Download link (https://www.dropbox.com/s/zk8x7ptg5mzmotk/test.zip?dl=0)

You need to use. AppDelegate
Objective C
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"LoginStatus"]) {
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.window.rootViewController = [storyboard instantiateViewControllerWithIdentifier:#"loginController"];
}else{
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.window.rootViewController = [storyboard instantiateViewControllerWithIdentifier:#"RootView"];
}
}
SWIFT - i hope its correct
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
//Using UserDefaults check already loggedin user or not
if (!someStatus) {
let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("someViewController") as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}else{
let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("loginViewController") as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
}

Related

How do you switch the root view controller of UINavigationController when signing out the user (Swift 5)

I am trying to make it so that my initial root view controller is the HomeViewController. Then I run a code to check if the user (I am using Firebase) is logged on already. If the user is not logged on, then the root view controller will change to the LoginViewController and modally present the Login/Register screens and then release those VCs once the user has signed in.
func authenticateUserConfigureView() {
if Auth.auth().currentUser == nil {
DispatchQueue.main.async {
let navController = UINavigationController(rootViewController: LoginViewController)
navController.navigationBar.barStyle = .default
self.present(navController, animated: true, completion: nil)
}
} else{
configureViewComponents()
}
}
it seems like if I write the code rootViewController: LoginViewController this error shows up
Cannot convert value of type 'LoginViewController.Type' to expected argument type 'UIViewController'
Alternatively, If I write LoginViewController() then although it seems like the user gets directed to the Login view controller, the simulator immediately crashes.
UPDATE
I tried using
let homeViewController = self.storyboard?.instantiateViewController(identifier: Constants.Storyboard.homeViewController) as? HomeViewController
view.window?.rootViewController = homeViewController
view.window?.makeKeyAndVisible()
but nothing seems to happen at all (though it seems to run). I am using the main storyboard to create my view controllers by the way.
It's simple to solve, you need pass an ViewController instance, you can get from your Login StoryBoard, this way:
let loginViewController = UIStoryboard (name: "LoginStoryboardName", bundle: Bundle.main).instantiateInitialViewController()
let navController = UINavigationController(rootViewController: loginViewController )
UIApplication.shared.keyWindow?.rootViewController = navController
To work, in Login storyboard, your viewController needs to be set to InitialViewController.
If your Storyboard already has a NavigationController, you can just pass the ViewController instance to the rootViewController, this way:
let viewController = UIStoryboard (name: "LoginStoryboardName", bundle: Bundle.main).instantiateInitialViewController()
UIApplication.shared.keyWindow?.rootViewController = viewController
Hope this helps.

Black screen when changing root view controller in AppDelegate

I am trying to change the root view controller from the app delegate's didFinishLaunchingWithOptions, depending on whether the user is logged in or not. Once I get past this condition, I am using the following code to change root view controllers:
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SWRevealViewController") as! SWRevealViewController
self.window?.makeKeyAndVisible()
However, when I launch the app (with a valid logged in user) the simulator first shows the log in screen (old root view controller) for a second, then the screen goes black for about 30 seconds to a minute, before finally showing the desired view controller.
The view controller structure in storyboard is as follows:
SWRevealViewController -> Navigation Controller -> Desired View Controller (new root)
The reason for beginning with SWRevealViewController is because the slide menu is lost otherwise.
Any ideas of what might be going on?
I found a way to produce a similar result to the one I desired. It involves not changing the root view controller at all, and having it present an "artificial root view controller" after launch:
if let currentRoot = self.window?.rootViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let artificialRoot = storyboard.instantiateViewController(withIdentifier: "SWRevealViewController")
currentRoot.present(artificialRoot, animated: false, completion: nil)
}
Although not ideal, the results of this implementation are by far better than the implementation in the question description.
Here is an example, that works for me, just make your loginViewControllers to be a stack of UINavigationController, not related to SWRevealController. It is easy workaround.
self.window = UIWindow(frame: UIScreen.main.bounds)
if User.shared.firstLaunch {
let navigationVC = Storyboard.inital.instantiateViewController(withIdentifier: "firstLaunchNC") as! UINavigationController
self.window?.rootViewController = navigationVC
} else if User.shared.token == "" {
let navigationVC = Storyboard.inital.instantiateViewController(withIdentifier: "initialVC") as! UINavigationController
self.window?.rootViewController = navigationVC
} else {
self.registerForPushNotifications(application: UIApplication.shared)
User.shared.refreshToken()
let revealController = Storyboard.main.instantiateViewController(withIdentifier: "revealViewController") as! SWRevealViewController
self.window?.rootViewController = revealController
}
self.window?.makeKeyAndVisible()
return true
try this:
let viewController = ViewController()
let navigationController = UINavigationController(rootViewController: viewController)
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
try this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UITabBarController *tbc = [storyboard instantiateViewControllerWithIdentifier:#"TabBarController"];
tbc.selectedIndex=[singleton getSelectedTabIndex];
// tbc.selectedIndex=0;
//self.window.rootViewController = tbc;
[self.window setRootViewController:tbc];
[UIView transitionWithView:self.window duration:0.3 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil
completion:nil];
If This not work..Please check your initial Controller ...In Which Never try Load NSAtrributedString
NSAttributedString *attrStr = [[NSAttributedString alloc]
initWithData:[htmlString dataUsingEncoding:NSUnicodeStringEncoding]
options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: #(NSUTF8StringEncoding)}
documentAttributes:nil
error:nil];
Note:-- Black Screen Apear When Initial Controller ViewDidLoad Take Some time to load UIview into Memory due some Lazy UI loading Assests are done in ViewDidLoad...
Try heavy load view cide into ViewWillApear or ViewDidApear ....

Swift showing view only on first launch with navigation controller

I have some code to only show the first view controller in my storyboard on the first launch of the app. After that I want to skip that page and go straight to my second view on each launch. I have embedded the first view (which is connected to the second) in a navigation controller.
My issue is that after the first launch when the app goes to the second view directly it's showing the view without the navigation bar on top and I'm not sure why.
In my appdelegate:
func firstLaunchCheck(){
let launchedBefore = UserDefaults.standard.bool(forKey: "launchedBefore")
if launchedBefore{
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initialView : UIViewController = storyboard.instantiateViewController(withIdentifier: "mainScreen") as UIViewController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialView
self.window?.makeKeyAndVisible()
}
else{
UserDefaults.standard.set(true, forKey: "launchedBefore")
}
}
UPDATE:
I wound up just changing which view controller were embedded in the navigation controller (excluded the first one) since it didn't make sense to me to have it there. So now after the first launch it loads the navigation controller
SecondViewController is not added in UINavigationController hierarchy, to see the navigationBar on top you can push SecondViewController on firstVC if the launchedBefore is false in appDelegate
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondVC = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
let navigationController = window.rootViewController as! UINavigationController
navigationController?.pushViewController(secondVC, animated: false)
You need to embed the second view controller i.e. "mainScreen" in UINavigationController and then make it the rootViewController of your app window.
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let navigationController = UINavigationController.init(rootViewController: storyboard.instantiateViewController(withIdentifier: "mainScreen"))
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialView
self.window?.makeKeyAndVisible()

How to represent a startup screen in Storyboards

Right now I have a MainViewController which is embedded in a UINavigationController so the navigation controller is set as initial view controller.
What I want is first time the app starts and only then to show a StartupViewController. But I am not sure how to represent this in my storyboard.
Should this be set as initial view controller if the app starts the first time, if not the navigation controller should be set.
What I tried is to show StartupViewController in MainViewController::viewDidLoad(), but its not working how I wanted too.
Anyone know what is the right approach to do this ?
Hello this code may be helpfull for you :
// MARK: - Application Supporting Funcations -
func loadFirstViewController(viewController: String)
{
// for loading first view Controller
let storyBoard = appDelegate.AppStoryBoard()
/////////////////////////Add Navigation Controller and set Root View Controller///////////////////////////////////////
let object = storyBoard.instantiateViewControllerWithIdentifier(viewController) // for prelogin navigation
self.navigationController = UINavigationController(rootViewController: object)
self.navigationController?.navigationBar.hidden = true
self.loadNavigationControllerToWindow()
}
func loadNavigationControllerToWindow()
{
if self.window == nil
{
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
}
// for loading root view
self.window!.rootViewController = self.navigationController!
self.window!.makeKeyAndVisible()
}
call this function in didFinishLaunchingWithOptions
if((NSUserDefaults.standardUserDefaults().valueForKey("isFirstTime") != nil))
{
self.loadFirstViewController("LoginVC") // for loading first view controller
}
else
{
self.loadFirstViewController("WelcomeVC") // for loading first view controller
}
put this after you go in second controler viewDidLoad
if((NSUserDefaults.standardUserDefaults().valueForKey("isFirstTime") == nil))
{
NSUserDefaults.standardUserDefaults().setValue("1", forKey: "isFirstTime")
}
This is how I acheived in my app.
Add this in appdelegate applicationdidfinishlaunching.
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
if (![defaults boolForKey:#"FirstTime"])
{
//NSLog(#"Enter First Time ");
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]];
StartupViewController * firstViewController = [storyBoard instantiateViewControllerWithIdentifier:#"StartupViewController"];//AskAndAnswerViewId RegisterViewId TagViewId HelpViewId
self.navigationController=[[UINavigationController alloc]initWithRootViewController:firstViewController];
self.window.rootViewController = self.navigationController;
[self.navigationController setNavigationBarHidden:YES];
}
else
{
//NSLog(#"not First Time");
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]];
HelpViewController *mainviewcontroller = [storyBoard instantiateViewControllerWithIdentifier:#"AskAndAnswerViewId"];
self.navigationController=[[UINavigationController alloc]initWithRootViewController:mainviewcontroller];
self.window.rootViewController = self.navigationController;
[self.navigationController setNavigationBarHidden:YES];
}
Once you reached in Mainviewcontroller change the userdefault value for FirstTime to "NO".
I understand your Question ,
In AppDelegate try to set rootViewController ,
I have store data in the NSUserDefault if user came first time
And try to set rootViewController once he visit first time.
In below Example I have navigate user to Login screen/Home screen
let str = userDefaults.objectForKey("firstTime")
{}else{}
Please don't forget to give identifier to your view controller StartupViewController
-> user interaction enable in StartupViewController
if (UserDefaults.standard.string(forKey: "keepUsername") != nil) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "Revealview")
self.present(vc, animated: false, completion: nil)
}
else
{
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "loginview") as! loginview
self.present(nextViewController, animated:true, completion:nil)
}

Implementing SWRevealViewConroller Library (slide out menu) in multiple storyboards

I am trying to implement SWRevealViewController Library as given in VideoTutorial, I was successfully able to do that but I don't want everything on 1 storyboard, I want to break it down in 2 storyboards
AppDelegate Code:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
storyboard = UIStoryboard(name: "MenuDrawer", bundle: nil)
initialViewController = storyboard.instantiateViewControllerWithIdentifier("SWRevealViewController") as! UIViewController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
Rightnow MenuDrawer storyboard has everything
SWRevealViewCOntroller
TableViewController
NavigationController
RootViewController
and below segues which are defined in Library:
segue1 (sw_rear) : between SWRevealViewController --> TableViewController
segue2 (sw_front) : between SWRevealViewController
--> NavigationController
now I want 3 and 4 in different storyboard. but when I move 3 and 4 to different storyboard how do I create segue 2 across storyboards
I am not really sure if I understand your problem but you can try this to retrive your second storyboard and load your navigationViewController from there.
let storyBoard : UIStoryboard = UIStoryboard(name: "SecondStoryBoard", bundle:nil)
let deleteViewController = storyBoard.instantiateViewControllerWithIdentifier("SecondNavigationController") as UINavigationController
as far as iknow, you don't need to push again the segue 2 on 3 and 4. what you need is refer the new view (3 and 4) on the segue 2. in Obj-c will be like that:
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SWRevealViewController *view = [mainStoryboard instantiateViewControllerWithIdentifier:identifier];
[view setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self.navigationController pushViewController:view animated:YES];
where "self" is the ViewController where segue 2 has been created.
i hope have answered your question.
Try This First Of All Make the other storyboard and add what you need then call the other storyboard in
AppDelegate Code:
func application(application: UIApplication,didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
var storyboard = UIStoryboard(name: "MenuDrawer", bundle: nil)
var storyboard1 = UIStoryboard(name: "NewStoryBoardName", bundle: nil)
var initialViewController = storyboard.instantiateViewControllerWithIdentifier("SWRevealViewController") as! UIViewController
var initialViewController1 = storyboard1.instantiateViewControllerWithIdentifier("SWRevealViewController") as! UIViewController
self.window?.rootViewController = [initialViewController,initialViewController1]
self.window?.makeKeyAndVisible()
return true
}
You can not create segues between storyboards using Interface Builder.
It is only possible programmatically, example:
let storyBoardTwo = UIStoryboard(name: "storyBoardTwo", bundle: nil)
// Pick a view controller using it's identifier string set in Interface Builder.
let myVC = storyBoardTwo.instantiateViewControllerWithIdentifier("aViewController") as! UIViewController // Or use more specific (custom) type
// Push it to the navigation controller
self.navigationController.pushViewController(myVC, animated: true)
pushViewControllerwill simply put the myVC on top. This code is what a segue will end up doing. You can put this code anywhere in an existing ViewController, on a button tap IBAction or where ever needed.
If the pushed ViewController have any segues (from Storyboard or code) they will still work, as expected.
This of course works if you would want to programmatically load ViewController from one and the same Storyboard as well.

Resources