performSegue before the View is visible - ios

I have two views
ViewController-> Main view
LoginVC -> LogIn View
My initial view is ViewController which contains buttons and some text.
What i want to achive
Perform a segue that will transfer the view to Login if the user is not yet log in.
What i have done
Inside my ViewController I did a check if USER_ID is nil then if its a nil then i will perform a segue.
override func viewWillAppear(animated: Bool) {
if Globals.USER_ID == nil{
self.performSegueWithIdentifier("goto_login", sender: nil)
// dispatch_async(dispatch_get_main_queue(), {
// self.performSegueWithIdentifier("goto_login", sender: nil)
// })
}
}
What is my problem
My Problem is whether I use viewWillAppear or viewDidLoad or viewDidAppear to transfer view from ViewController to LoginVC.ViewController will be visible in a single second before the the login screen appears and i want to get rid of it.Can someone help me solve this issue.

I have same functionality in my App. I achieved it by checking for userID in AppDelegate.swift inside function func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
So, delete the segue and your modified code will look like as follows:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
if Globals.USER_ID == nil{
let loginScreen = storyBoard.instantiateViewControllerWithIdentifier("LoginVC")
self.window?.rootViewController = loginScreen
}else{
let mainScreen = storyBoard.instantiateViewControllerWithIdentifier("ViewController")
self.window?.rootViewController = mainScreen
}
return true
}
This way you will not need any of the method like viewDidLoad(), viewDidAppear() or viewWillAppear()to be used for this purpose.
Just as an addition to this answer - Use the instance of AppDelegate again after logout happens. For example you should do following in logout method:
func logout() {
if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
Globals.USER_ID = nil
appDelegate.window?.rootViewController = loginScreen
}
}
This way you can clear the userID and navigate back to login screen after the user logouts.

Related

How can I pass data loaded when my application finished launching thru my UITabBar to a UITableView?

I am a new iOS programmer and I am trying to make an application that involves the following flow:
-> UITabBar -> UINavController -> UITableViewController.
Initially the program was working when I have the following flow:
-> UINavController -> UITableViewController
But when I added the UITabBar (with the Embed In method)the I had two issues:
1) Casting the initial view from UITableView to UITabBarView
2) The data which have been restored from Archives of the phone are not loading in the TableView.
I managed to fix the casting issue with the UIStoryboard IDs, but I am not sure if this way I created the second problem of not passing data to the UITableView correctly.
The Casting problem has taking place at the appDelegate code. Here is the original code I had before incorporating the UITabBarView:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let navController = window!.rootViewController as! UINavigationController
let SLBprojectController = navController.topViewController as! GR8TableView
SLBprojectController.SLBprojectDB = thisSLBprojectDB
return true
}
The problem with the above code was that it told me that it could not cast a TableViewController (GR8TableView) into a UITabBarView. I have managed to fix this by searching in the StackOverflow forums by making the following:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarIntial : UITabBarController = mainStoryboardIpad.instantiateViewController(withIdentifier: "TabBar") as! UITabBarController
let navigationController:UINavigationController = mainStoryboardIpad.instantiateViewController(withIdentifier: "navController") as! UINavigationController
let navigationController1:UIViewController = mainStoryboardIpad.instantiateViewController(withIdentifier: "ViewController1")
let SLBprojectController = navigationController.topViewController as! GR8TableView
SLBprojectController.SLBprojectDB = thisSLBprojectDB
tabBarIntial.viewControllers = [navigationController, navigationController1]
tabBarIntial.selectedIndex = 0
return true
}
But after I fixed the "casting" issue then I am getting problems loading the data in the TableView. Not sure if this problem is related to the way I fixed the casting issue.
Any assistance would be much much appreciated!
The simplest answer would be to go back to logic similar to what worked for you, but with a slightly more complex relationship. For example, I created an app with a tab bar controller, a navigation controller in the first tab, and a FirstViewController embedded in the navigation controller.
Since I don't have a database, I gave the FirstViewController a single instance variable called running.
The following code finds the controller and sets the variable:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if let tabController = window!.rootViewController as? UITabBarController {
if let navController = tabController.viewControllers![0] as? UINavigationController {
if let firstController = navController.topViewController as? FirstViewController {
firstController.running = true
} else {
print("Unexpected controller in navigation hierarchy: \(String(describing: navController.topViewController))")
}
} else {
print("Unexpected contained controller: \(String(describing: tabController.viewControllers![0]))")
}
} else {
print("Unexpected root controller: \(String(describing: window!.rootViewController))")
}
return true
}
Note that I'm not creating any new controllers. That's all done by default storyboard loading.
I believe you should be able to adapt this to your own variable and class names.

Firebase + Swift: Bypass User Login Screen

So i'm working on a new app and i'm using Firebase to manage all the backend stuff with user logins etc, i've created a login/signup screen for the users when they load the app. What i'm trying to do is load the HomeScreenVC if the user is already logged in and if the user isn't then they would be directed to the login/register vc.
I kind of have it working in the sense that it works if the user is already a currentUser but the issue i'm having is that if the user has never loaded the app then it crashes as it can't detect currentUser.
My code I have in the AppDelegate is:
var window: UIWindow?
var storyboard: UIStoryboard?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
FIRApp.configure()
self.storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let currentUser = FIRAuth.auth()?.currentUser!
if currentUser != nil
{
self.window?.rootViewController = self.storyboard?.instantiateViewControllerWithIdentifier("tabVC")
}
else
{
self.window?.rootViewController = self.storyboard?.instantiateViewControllerWithIdentifier("loginScreen")
}
return true
}
This is the error i get: here
Any help would be great! I'm using the latest version of Firebase and Swift 2.
You are force unwrapping nil on that line, causing the crash. Remove the ! from FIRAuth.auth()?.currentUser!
update for swift 3 and firebase 4.8
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.statusBarStyle = .lightContent
// Override point for customization after application launch.
// add firebase
FirebaseApp.configure()
// check user status then set initial Viewcontroller
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let startMainVC = storyboard.instantiateViewController(withIdentifier: "MainVC")
let startIntroVC = storyboard.instantiateViewController(withIdentifier: "IntroVC")
// check if user is logged
if authProvider.Instance.userStatus() == true{
self.window?.rootViewController = startMainVC
}
else
{
self.window?.rootViewController = startIntroVC
}
return true
}

How to Pass Values from Separate Classes to AppDelegate?

I have a class in my SignInViewController.swift:
class CredentialState: NSObject {
static let sharedInstance = CredentialState()
var signedIn = false
var displayName: String?
var photoUrl: NSURL?
}
I would like to use the variable signedIn to authenticate users in AppDelegate with an if-else statement. Currently, I have a way to set the viewcontroller to CustomTabBarController (custom programmatically made) or SignInViewController (storyboard made). The if statement would basically say if the value is false set the controller to the sign in screen and if it's true then go to the tab bar screen.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
FIRApp.configure()
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.makeKeyAndVisible()
// Main view controller is inside of customtabbarcontroller, which gives a tab overlay
// window?.rootViewController = CustomTabBarController()
// Sets the main view to a storyboard element, such as SignInVC
let storyboard = UIStoryboard(name: "SignIn", bundle: nil)
let loginVC = storyboard.instantiateViewControllerWithIdentifier("SignInVC") as! SignInViewController
self.window?.rootViewController = loginVC
return true
}
if i understood you correctly:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
FIRApp.configure()
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.mainScreen().bounds)
// check login state
if CredentialState.sharedInstance.signedIn {
// Main view controller is inside of customtabbarcontroller, which gives a tab overlay
window?.rootViewController = CustomTabBarController()
} else {
// Sets the main view to a storyboard element, such as SignInVC
let storyboard = UIStoryboard(name: "SignIn", bundle: nil)
let loginVC = storyboard.instantiateViewControllerWithIdentifier("SignInVC") as! SignInViewController
window?.rootViewController = loginVC
}
window?.makeKeyAndVisible()
return true
}
I am not so sure of what you are asking, yet I'll try to answer that. Basically what you need to do is just simply have this piece of code above your CredentialState class:
credentialState : CredentialState = CredentialState()
In this way you can change or check your signedIn variable from AppDelegate. So simply in the AppDelegate file you can:
if(credentialState.signedIn == true) ...
Hope I was able to answer your question

Using tab bar controller as the root view controller and present sign in view controller if user is not logged in

I've read that the tab bar controller of a project should always be the base controller, but I'm wondering, how do I present my sign in view controller if user is not logged in, then dismiss after user is logged in?
The following is my code
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController = storyboard.instantiateViewControllerWithIdentifier("signInViewController") as! SignInViewController
self.window?.makeKeyAndVisible()
self.window!.rootViewController!.presentViewController(loginViewController, animated: true, completion: nil)
return true
}
It does work as expected but I'm having this shown in my console.
2016-01-07 12:37:58.139 Fingers[461:67210] Presenting view controllers on detached view controllers is discouraged <AppName.HomeViewController: 0x13ed4f8f0>.
2016-01-07 12:37:58.149 Fingers[461:67210] Unbalanced calls to begin/end appearance transitions for <UITabBarController: 0x13ed4ed60>.
Also this will trigger the view did load on the root view controller, is there any way to avoid that?
It is very easy to do that using NSNotificationCenter.
Just register a notification in your TabBarViewController with a method which presents a login viewcontroller.
let vc = ViewController() //change this to your class name
self.presentViewController(vc, animated: true, completion: nil)
Then if the isLogged flag is NO, you can post a notification to trigger above method.
After logged, just dismiss that.
self.dismissViewControllerAnimated(true, completion: {});
Here's a simple example for Firebase using the App Delegate's didFinishLaunchingWithOptions method
application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
var window: UIWindow?
if Auth.auth().currentUser == nil {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let authVC = storyboard.instantiateViewController(withIdentifier: "AuthVC")
window?.makeKeyAndVisible()
window?.rootViewController?.present(authVC, animated: true, completion: nil)
return true
}
//other things to do at launch if applicable
return true
}

How to check NsUserDefaults from launch screen in IOS?

I am new in iOS application development. In my application I have a launch screen,login page and a home page. The launch screen is in separate storyboard and I want to check NSUserDefaults from launch screen to decide the user already logged in or not or how to check NSUserDefaults to bypass login screen to home screen.
If with launch screen you mean the a storyboard that is displayed while the app is starting then you are out of luck.
Since your app is starting, no code is run and you can not launch anything. You will have to do this is UIApplicationDelegate.
What are you looking for is the application(_:didFinishLaunchingWithOptions:) method in the AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// check whatever, so I can decide which ViewController should be the rootViewController
return true
}
you can access the NSUserDefaults in AppDelegate Class, and also you need to access your ViewController from storyboard to show as home screen.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if (NSUserDefaults.standardUserDefaults().objectForKey("login") == nil)
{
NSUserDefaults.standardUserDefaults().setBool(false, forKey: "login")
}
if (NSUserDefaults.standardUserDefaults().boolForKey("login") == true)
{
do {
let arr1 = try UserProfileDataHelper.find("1")
if arr1?.Type == "Customer" {
currentUser = "Customer"
screenlaunch("MENU")
}else{
currentUser = "Store"
screenlaunch("HOME")
}
} catch _{}
}
return true
}
func screenlaunch(str : String )
{
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let homeViewController = mainStoryboard.instantiateViewControllerWithIdentifier(str)
let navigationController :UINavigationController = UINavigationController(rootViewController: homeViewController)
navigationController.navigationBarHidden = true
window!.rootViewController = nil
window!.rootViewController = navigationController
window?.makeKeyWindow()
}

Resources