Dismissing initial ViewController - ios

I am developing an app using swift 3 . I launch a tutorial like view controller on the first launch of my app and close it using a button .But the inital view controller does not get dismissed even when i click the close button. I know the question sounds familiar but i am unable to get a correct solution for it .
Here's the code of the the AppDelegate
import UserNotifications
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application:
UIApplication,didFinishLaunchingWithOptions launchOptions: [
UIApplicationLaunchOptionsKey: Any]?) -> Bool
{
let launchedBefore = UserDefaults.standard.bool(forKey: "launchedBefore")
if launchedBefore {
print("This is not the first Launch")
} else
{
print("First Launch, setting UserDefaults")
UserDefaults.standard.set(true, forKey: "launchedBefore")
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let initiaView = storyBoard.instantiateViewController(withIdentifier: "FirstLaunchViewController")
self.window?.rootViewController = initiaView
self.window?.makeKeyAndVisible()
}
return true
}
Here's my code from the initialViewController
class FirstLaunchViewController:UIViewController
{
override func viewDidLoad() {
}
#IBAction func doneButtonTapped(_ sender: Any)
{
_ = navigationController?.popViewController(animated:true)
}
}

Try this
let rootViewController = self.window?.rootViewController // this is your initial viewcontroller set initial viewcontroller in storyboard
let initiaView = storyBoard.instantiateViewController(withIdentifier: "FirstLaunchViewController")
rootViewController.pushViewController(initiaView, animated: true)

Try setting the view controller as root view controller for window which you want to show after dismissing the initial view controller. Present the initial view controller from window root view controller

Related

How do I dismiss a rootViewController before presenting a new UITabBarController?

I've set up a UIViewController as my rootViewController in AppDelegate, however, when a user logs in or skips it I am presenting a UITabBarController over the top.
I need to dismiss the LoginController, and set the UITabController as rootViewController instead after user logs in.
How can I go about reorganizing this?
AppDelegate()
window = UIWindow()
window?.makeKeyAndVisible()
window?.rootViewController = LoginController()
LoginController()
self.present(MainTabBarController(), animated: true, completion: nil)
you can design your code like this.
This one
It's too easy to maintain condition for user logged in or not, and then based on that status. You can navigate to your view.
You can try this way :
1.In AppDelegate you can these methods.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let isLogin = UserDefaults.standard.bool(forKey: "IS_LOGIN")
if isLogin == true {
self.goToDashboardView()
} else {
self.goToLoginView()
}
return true
}
//MARK:- ------- Global Methods -------
class func sharedInstance() -> AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
func goToLoginView() {
let sb = UIStoryboard.init(name: "Main", bundle: nil)
let loginVC = sb.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
let navVC = UINavigationController(rootViewController: loginVC) // You can skip this if you do not want to add navigation bar
self.window?.rootViewController = navVC // if you skipped above line, then you have to assign 'loginVC' here.
self.window?.makeKeyAndVisible()
}
func goToDashboardView() {
let sb = UIStoryboard.init(name: "Main", bundle: nil)
let tabbarVC = sb.instantiateViewController(withIdentifier: "MyTabBarController") as! MyTabBarController
self).window?.rootViewController = tabbarVC // if you skipped above line, then you have to assign 'loginVC' here.
self.window?.makeKeyAndVisible()
}
2.In LoginViewController, when user logged in successfully.
#IBAction func btnLoginClicked(_ sender: UIButton) {
// Your API call or other code
// If all things goes well, then login and go to dashboard
UserDefaults.standard.set(true, forKey: "IS_LOGIN")
AppDelegate.sharedInstance().goToDashboardView()
}
3.And finally, whenever and from wherever you want to log out from app, just call below code.
#IBAction func btnLogOutClicked(_ sender: UIButton) {
// Your API call or other code
// If all things goes well, then logout and go to login view
UserDefaults.standard.set(false, forKey: "IS_LOGIN")
AppDelegate.sharedInstance().goToLoginView()
}
4.And Main.storyboard should have design something like :
you do not need to present the UITabBarViewController and then dismiss the LoginViewController, you just need to reset the UITabBarViewController as a rootViewController for you app after login or skip as the following:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
// Override point for customization after application launch.
let yourTabBar = UIStoryboard(name: "YOUR_STORYBOARD_NAME", bundle: nil).instantiateViewController(withIdentifier: "YOUR_UITABBARCONTROLLER_ID")
self.window!.rootViewController = yourTabBar
self.window!.makeKeyAndVisible()
return true
}

why my nav controller is nil even after embedding navigation controller in story board and using push segue?

I have tried to read several threads on Stackoverflow, but I think that I have implemented all of them but still it doesn't work. here is my storyboard
so I hide (uncheck) the navigation bar visibility like the image below, because I want to implement my own 'navigation header' like in the image above (in the right) :
and when the back button is pressed, I use the code below:
self.navigationController?.popViewController(animated: true)
but unfortunately, after I check, the navigation controller is nil and I can't get back to previous VC.
I set some code in the app delegate like this, in order to set the navigation. if the user has already login then it will be navigated to HomeVC (main tab bar), otherwise it will be directed to login sequence like my storyboard above
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// to print Local Database Location, uncomment the line below if you want to trace the location of Realm Database / User Default
// print("Location of Realm Database: \(Realm.Configuration.defaultConfiguration.fileURL)")
checkHasLoggedInOrNot()
return true
}
}
extension AppDelegate {
// MARK: - Helper Methods
func checkHasLoggedInOrNot() {
let userHasLoggedIn = AuthService.shared.hasLoggedIn
if userHasLoggedIn {
goToMainTabBar()
} else {
goToAuthVC()
}
}
}
extension AppDelegate {
// MARK: - Navigation
func goToMainTabBar() {
let storyboard = UIStoryboard(name: StoryBoardName.Main.rawValue, bundle: nil)
let mainTabBar = storyboard.instantiateViewController(withIdentifier: MainStoryboardData.StoryBoardID.MainTabBar.rawValue)
window?.rootViewController = mainTabBar
}
func goToAuthVC() {
let storyboard = UIStoryboard(name: StoryBoardName.Auth.rawValue, bundle: nil)
let authVC = storyboard.instantiateViewController(withIdentifier: AuthStoryboardData.StoryBoardID.AuthVC.rawValue)
window?.rootViewController = authVC
}
}
maybe the problem is the code below ?
func goToAuthVC() {
let storyboard = UIStoryboard(name: StoryBoardName.Auth.rawValue, bundle: nil)
let authVC = storyboard.instantiateViewController(withIdentifier: AuthStoryboardData.StoryBoardID.AuthVC.rawValue)
window?.rootViewController = authVC
}
because it is pointed to AuthVC ? not to Navigation Controller ?
what went wrong in here ?
Push/Pop only be possible if there is Navigation stack in window.
Replace your goToAuthVC with following -
func goToAuthVC() {
let storyboard = UIStoryboard(name: StoryBoardName.Auth.rawValue, bundle: nil)
let authVC = storyboard.instantiateViewController(withIdentifier: AuthStoryboardData.StoryBoardID.AuthVC.rawValue)
let navigationController = UINavigationController(rootViewController: authVC)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
}

How to maintain login session in ios?

I would like to know where I need to change the root view controller in the app programming. Below is my code
class NavigationViewController: UINavigationController {
var window: UIWindow?
override func viewDidLoad() {
super.viewDidLoad()
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let newRootView = storyBoard.instantiateViewController(withIdentifier: "WelcomeViewController") as! WelcomeViewController
let userStatus = UserDefaults.standard.bool(forKey: "isLoggedIn")
if userStatus {
self.window?.rootViewController = newRootView
}
}
}
I am setting the value for isLoggedIn key as true when user logged in and false when the user logged out so that I can retrieve the value in this navigation controller subclass, based on that I can choose the root view controller. But its not working fine it remains the same whenever I am launching the app I am getting the login page only though I already logged in, also please don't suggest me to change the root view controller inside of didfinishlaunchingwithoptions method. Could someone help me to solve it? Thanks in advance.
If I understand correctly the goal of your code, you want to boot directly on WelcomeViewController if the user is already logged in.
You could try to create a custom segue called ReplaceSegue and set this ReplaceSegue to the segue linking the NavigationViewController and the ViewController.
And then you can change the destination of your segue.
class ReplaceSegue: UIStoryboardSegue {
override func perform() {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let newRootView = storyBoard.instantiateViewController(withIdentifier: "WelcomeViewController") as! WelcomeViewController
sourceViewController.navigationController?.setViewControllers([newRootView], animated: true)
}
}
First set user login bool true in NSUserDefults. when User is login Successfully.
UserDefaults.standard.set(true, forKey: "USERISLOGIN")
Now Open Appdelegate.swift -> didFinishLaunchingWithOptions Method:-
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if(UserDefaults.standard.bool(forKey: "USERISLOGIN")){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let objLogoutVC = storyboard.instantiateViewController(withIdentifier: "LogoutVC") as! LogoutVC
let navigationController = UINavigationController(rootViewController: objLogoutVC)
navigationController.navigationBar.isTranslucent = false
navigationController.navigationBar.isHidden = true
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
}
return true
}
Let me know if you needed any thing more.

How to open a page view controller in my iOS app only the first time the app runs?

I am creating an app for iOS and I want to open a page view controller (not a normal view controller) but only the first time that a user opens the application.
The problem is that I can't open a new page view controller within the code. The first screen that the users will see is the login screen, but on first visit switch to the page view controller.
This is what I have so far in the login screen viewcontroller:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let launchedBefore = NSUserDefaults.standardUserDefaults().boolForKey("launchedBefore")
if launchedBefore {
//Not the first time, show login screen.
}
else {
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "launchedBefore")
//First time, open a new page view controller.
}
let secondViewController:InstructionViewController = InstructionViewController()
self.presentViewController(secondViewController, animated: true, completion: nil)
}
The page view controller that I want to open is already created on the storyboard.
App delegate's willFinishLaunchingWithOptions method would be the best place (AFAIK). check the condition and set window's root view controller accordingly.
With the other answers I was able to solve the problem.
In the appDeligate file you need to replace the first function with this:
var window: UIWindow?
var storyboard:UIStoryboard?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.makeKeyAndVisible()
let launchedBefore = NSUserDefaults.standardUserDefaults().boolForKey("launchedBefore")
if launchedBefore {
//Not the first time, show login screen.
storyboard = UIStoryboard(name: "Main", bundle: nil)
let rootController = storyboard!.instantiateViewControllerWithIdentifier("Login")
if let window = self.window {
window.rootViewController = rootController
}
}
else {
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "launchedBefore")
//First time, open a new page view controller.
storyboard = UIStoryboard(name: "Main", bundle: nil)
let rootController = storyboard!.instantiateViewControllerWithIdentifier("Instruction")
if let window = self.window {
window.rootViewController = rootController
}
}
return true
}
"Login" and "Instruction" are the names of the (page) view controllers.
I am not sure if this is most robust code but it works fine for me.
Here is Lesley's code updated to Swift 3:
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let launchedBefore = UserDefaults.standard.bool(forKey: "launchedBefore")
if launchedBefore {
//Not the first time, show login screen.
storyboard = UIStoryboard(name: "Main", bundle: nil)
let rootController = storyboard!.instantiateViewController(withIdentifier: "webView")
if let window = self.window {
window.rootViewController = rootController
}
}
else {
UserDefaults.standard.set(true, forKey: "launchedBefore")
//First time, open a new page view controller.
storyboard = UIStoryboard(name: "Main", bundle: nil)
let rootController = storyboard!.instantiateViewController(withIdentifier: "progressView")
if let window = self.window {
window.rootViewController = rootController
}
}
Don't forget to set the
var storyboard:UIStoryboard?
Before didFinishLaunchingWithOptions, and to set the identifiers similar to your own view controllers identifiers.

iOS Login Screen Modal on top of Tab Bar or Instantiated

I am developing an iOS App that has several Tabs. So I decided my root view Controller will be a Tab Bar Controller with 2 views.
I need the user to login as soon as the application starts, so I'm trying to find out the best approach to do this.
Following other similar questions posted here I've tried this 2 approaches:
Presenting the login screen as a Modal View on top of the Tab Bar Controller
Instantiating the Login view controller
I've done this, by using a UserisLoggedIn flag in NSUserDefaults that is set every time the user logs in or logs out.
The problem I face with both approaches is that before the login screen appears there's a quick flickr of the first view in the Tab Bar.
I've tried to resolve this setting the alpha value of the Tab Bar to 0 if the user is not logged in for the modal approach, but for the instance approach it doesnt work, it still flickers before showing the login screen. Anyway, I find this solution tedious and not really elegant.
There must be a standard approach for doing this in iOS, since you have loads of apps that present first a login screen, but since I am a beginner with iOS Programming I still don't know how to do it.
Here's some code from my Tab bar controller:
1st Approach
Tab Bar Controller
override func viewDidLoad() {
super.viewDidLoad()
view.alpha = 0
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") as NSString == "loggedIn"{
view.alpha = 1.0
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(false)
self.showLoginView()
}
func showLoginView(){
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") == nil{
self.performSegueWithIdentifier("loginView", sender: self)
}
}
Login View Controller
func updateUserLoggedInFlag() {
// Update the NSUserDefaults flag
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("loggedIn", forKey: "userLoggedIn")
defaults.synchronize()
}
#IBAction func login(sender: AnyObject) {
//Do my login here...
//If login successful:
self.performSegueWithIdentifier("dismissLogin", sender: self)
}
2nd Approach, Creating an Instance of the Login View Controller
1st View in the Tab Bar
override func viewDidAppear(animated: Bool){
super.viewDidAppear(true)
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") == nil{
let loginController: LoginViewController = self.storyboard?.instantiateViewControllerWithIdentifier("LoginViewController") as LoginViewController
self.tabBarController?.presentViewController(loginController, animated: false, completion: nil)
}
Login View Controller
#IBAction func login(sender: AnyObject) {
//Do my login here...
//If login successful:
self.dismissViewControllerAnimated(true, completion: nil)
}
OK here is what did the trick for me. I don't know if it's the right thing to do, but it seems to work. Like Joseph Duffy mentioned all I did was to set the Login view as the rootviewcontroller in the delegate, and once I was succesfully logged in, switch back to the tab bar controller as rootviewcontroller.
Code in AppDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") == nil{
showLogin()
}
}
func showLogin() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController") as LoginViewController
self.window?.makeKeyAndVisible()
self.window?.rootViewController = loginViewController
}
Code in LoginViewController
#IBAction func login(sender: AnyObject) {
//Do my login here...
//If login successful:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
self.dismissViewControllerAnimated(true, completion: nil)
appDelegate.window?.rootViewController = storyboard.instantiateViewControllerWithIdentifier("tabBarID") as TabBarController
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") == nil{
showLoginView()
}
func showLoginView(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController: LoginViewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController") as LoginViewController
self.window?.makeKeyAndVisible()
self.window?.rootViewController?.presentViewController(loginViewController, animated: true, completion: nil)
}
Take a look at a similar question's answer. The solution is to do this check in your app delegate's application:didFinishLaunchingWithOptions: method by checking if the user is logged in and loading the login view from a storyboard when necessary.
I have created a blank project, added a view controller with a storyboard identifier of loginScreen and have the following code in the app delegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
self.showLogin()
return true
}
func showLogin() {
//loginScreen
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController = storyboard.instantiateViewControllerWithIdentifier("loginScreen") as UIViewController
if let window = self.window {
window.makeKeyAndVisible()
window.rootViewController?.presentViewController(loginViewController, animated: false, completion: nil)
}
}
This shows the login screen and the main screen is not seen.

Resources