Is there a way to perform a conditional segue in a swift ViewController? - swift

I am attempting to authenticate user sign in using Firebase. If a user's credentials are verified, I am seguing to the home screen of my application within an if-else statement using user and error. However, performSegue(...) executes whether or not the log in actually occurred.
I am certain that the problem is not with verification/login/logout issues in Firebase or with the textfields.
Here is my code:
func handleSignIn(username:String, password:String) {
Auth.auth().signIn(withEmail: username, password: password) { user, error in
if error == nil && user != nil {
//self.dismiss(animated: false, completion: nil)
print("Logged in!")
self.performSegue(withIdentifier: "toHome", sender: nil)
} else {
print("Error logging in: \(error!.localizedDescription)")
}
}
}
Best,
Code Daddy

I have solved this issue.
The code above is actually correct and functional. The issue was that the handleSignIn method was called within:
#IBAction func didTapLogin(_ sender: Any) {...}
That button itself was the segue connection with the identifier "toHome," and so regardless of what the if/else block evaluated to, the application proceeded to the home menu.
Once I deleted and reestablished the segue "toHome" from the LoginViewController to the HomeViewController (not the Log In button to the HomeViewController), this code worked properly.

Related

Firebase not storing logged in user

Was working with Firebase for almost half year now and never had this issue. Using code just like before to create new user, he shows up in console, when i close app i can sign in but using same code as always it keeps prompting me for password. In first VC i have:
if let user = Auth.auth().currentUser {
performSegue(withIdentifier: "authorized", sender: self)
}
Which will check if there is auth token stored and perform segue to loading screen. However this never happens. The code is ran but doesn't do anything, no errors in compiler and no errors in console.
EDIT 1: also tried to create new project where i rewrote all the code getting same result, but my other project works without any issues, also i'm able to do anything else besides this using firebase such as access Firestore just not storing the user, went over all the documentation but couldn't find any solution.
EDIT 2: sign in code
if(email.text != "" && password.text != ""){
Auth.auth().signIn(withEmail: email.text!, password: password.text!) { user, error in
if(error == nil && user != nil) {
userID = (Auth.auth().currentUser?.uid)!
print("Signed in as: \(userID)")
self.performSegue(withIdentifier: "load", sender: self)
} else {
print("Error found: \(error?.localizedDescription)")
}
}
}
Solution:
DispatchQueue.main.async(){
if let user = Auth.auth().currentUser {
userID = (Auth.auth().currentUser?.uid)!
self.performSegue(withIdentifier: "authorized", sender: self)
}
}
Loaded with async so firebase will configure before checking for auth
The issue is likely that you are calling your code before firebase has properly initialized. I recommend using the entry view controller's viewDidAppear for things such as these. If you were using viewDidLoad, it is likely that firebase did not load yet.

Swift Firebase Login Registration auth

So when I first the page up I've kept it simple 2 text fields (email & password) 1 lbl 2 buttons (login register). Initially when I started out testing it everything worked when there was a problem an alert would pop up and tell you the problem, or you would be segue to next page based on button press and auth being complete.
But now every time I open the app to run code deeper inside no matter what I type I can sign in with the wrong password, or sign in with a previous email address even though previously these would both present errors. I have rebuilt this page numerous times over the week and decided to also add a get photo function from the users profile page.
Whenever I run the app and press a button I get this in the console:
Warning: Attempt to present on whose view is not in the window hierarchy!
I figure this is the problem because there is an error with the registration but the user is allowed to continue regardless. I've looked it up googled it read all the documentation I can find and even messed about trying and failing to put in a task structure.
PS I moved away from error label to use alerts hoping they would force a stop in the code
#IBAction func registerBtn(_ sender: Any) {
if emailTextField.text! == "" || passwordTextField.text == "" {
displayAlert(title: "Error", message: "Please Enter Your EMail Address & Choose A Password")
} else {
if let email = emailTextField.text {
if let password = passwordTextField.text {
//Create User
Auth.auth().createUser(withEmail: email, password: password, completion: { (user, error) in
// Auth.auth().createUserAndRetrieveData(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
self.displayAlert(title: "Error", message: error!.localizedDescription)
} else {
print("Registration Successful")
self.performSegue(withIdentifier: "registrationSegue", sender: nil)
}
self.login()
})
}
}
}
}
if error != nil {
// show your alert
}
You don’t need an else statement on authenticating your users. so delete that line
Also, if you’re presenting a view controller that’s supposed to be accessible by authenticated users.
Please try:
let HomePage = HomePageController() // Change this to your viewcontroller name
self.present(HomePage, animated: true, completion: nil)
swift 4 - Xcode 9.1
func signUP(){
Auth.auth().createUser(withEmail: emailIdTextField.text!, password: passworTextField.text!) { (user, error) in
print(user?.email)
}
}
func signIn(){
Auth.auth().signIn(withEmail: emailTextField.text!, password: passwordTextField.text!) { (user, error) in
print(user?.uid)
}
}
Swift 4.2
//creating user with email password authentication
Auth.auth().createUser(withEmail: emailTextfield.text!, password: passwordTextfield.text!) { (user, error) in
// completion handler
if error != nil {
print(error!)
} else {
//success
print("Registration Sucessful")
self.performSegue(withIdentifier: "goToChat", sender: self)
}
}

How to perform the Segue only after authorization with Touch ID

Maybe someone can help, just want to use Segue for Login button to made a transfer to second ViewController only after authorization with Touch ID but application still performing the Segue after user pressing on the button.
import UIKit
import LocalAuthentication
class LoginWindowViewController: UIViewController {
#IBAction func loginButton(_ sender: Any) {
let context: LAContext = LAContext()
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil){
context.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: "For login you need to use your TouchID", reply: {(wasSuccessful, error) in if wasSuccessful {
DispatchQueue.main.async {
self.shouldPerformSegue(withIdentifier: "LoginComplete", sender: self.navigationController)
}
}else{
print ("Bad TouchID")
}
})
}
}
Thanks
Try implementing this function and checking from where it's being called:
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
}
Remember that as you're calling the segue from your code, if you have already added a segue action from your button to the next ViewController in the storyboard you should remove it and only create a connection between your LoginViewController to the one you want to call
As the documentation states, if you do not override the shouldPerformSegue method, the default implementation returns true for all segues.
The shouldPerformSegue(withIdentifier:sender:) method should determine whether a segue with the specified identifier will or will not be called depending on the return value of your implementation.
Since you already check whether the TouchID authorization was successful, you don't actually need to call shouldPerformSegue, but rather you need to call performSegue.
context.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: "For login you need to use your TouchID", reply: {(wasSuccessful, error) in
if wasSuccessful {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "LoginComplete", sender: self.navigationController)
}
}else{
print ("Bad TouchID")
}
})

how to segue to 2nd page from successful login - "warning attempt to present on while a presentation is in progress" error

How do I segue to my 2nd page after successfully verifying login?
I have pulled a segue from the login page view controller (not the login button) to the next page and named the segue 'nextPage'. (If I segue from the login button then the button click allows all logins to segue through without testing them). When I segue from the login page it correctly checks details but does not segue to the next page on successful login, and instead I get the console error "Warning: Attempt to present on while a presentation is in progress!"
the code is
#IBAction func loginButtonTapped(sender: AnyObject) {
let userEmail = userEmailTextField.text;
let userPassword = userPasswordTextField.text;
let userEmailStored = NSUserDefaults.standardUserDefaults().stringForKey("userEmail");
let userPasswordStored = NSUserDefaults.standardUserDefaults().stringForKey("userPassword");
if userEmailStored == userEmail && userPasswordStored == userPassword {
// Login successful
// Display an alert message
displayMyAlertMessage("Login successful. Thank you");
NSUserDefaults.standardUserDefaults().setBool(true,forKey:"isUserLoggedIn");
NSUserDefaults.standardUserDefaults().synchronize();
print("login success!")
self.dismissViewControllerAnimated(true, completion:nil);
self.performSegueWithIdentifier("nextPage", sender: self);
} else if userEmailStored != userEmail {
// Login unsuccessful (email incorrect)
NSUserDefaults.standardUserDefaults().setBool(false,forKey:"isUserLoggedIn");
print("login unsuccessful. Incorrect email.")
// Display an alert message
displayMyAlertMessage("Incorrect login details.");
return;
} else if userPasswordStored != userPassword {
// Login unsuccessful (password incorrect)
// Display an alert message
displayMyAlertMessage("Incorrect login details");
//return;
NSUserDefaults.standardUserDefaults().setBool(false,forKey:"isUserLoggedIn");
print("login unsuccessful. Incorrect password.")
}
The login page comes after an initial 'protected' login/logout screen as ViewController.swift with this code
override func viewDidAppear(animated: Bool)
{
let isUserLoggedIn = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn");
if(!isUserLoggedIn)
{
self.performSegueWithIdentifier("loginView", sender: self);
}
}
#IBAction func logoutButtonTapped(sender: AnyObject) {
NSUserDefaults.standardUserDefaults().setBool(false,forKey:"isUserLoggedIn");
NSUserDefaults.standardUserDefaults().synchronize();
self.performSegueWithIdentifier("loginView", sender: self);
}
}
I do suggest to have a different approach on this.
If you set a storyboardID to LoginViewController you can directly manage to override the Protected page checking directly in AppDelegate.
For example you can try to do this
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
[...]
let isUserLoggedIn = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn")
if isUserLoggedIn {
let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let vc = storyboard.instantiateViewControllerWithIdentifier("IDYOUSETBEFORE")
window.rootViewController = vc
return
}
I recently managed to release a pod in order to easily handle this situations, have a look at StoryboardEnum lib
I solved this by removing the alert controller function, i.e. the code
displayMyAlertMessage("Login successful. Thank you");
as this was segueing to the 'login successful' popup view controller, instead of the segue that I needed, and in effect blocking the next page, while also not really necessary, as successful login means moving to the next page. I was able to still keep the alert/ popups for 'incorrect login details' which were the only essential alerts.

Segue not being called

I am trying to bypass a sign-in view if the user has already signed in once. I have run tests and know I'm getting to the right code. But the segue is never executed.
//bypass the sign in screen if user has already signed in
let signInCheck = NSUserDefaults.standardUserDefaults().valueForKey("editProfile")
if (signInCheck! .isEqual(1)) {
self.performSegueWithIdentifier("loggedIn2", sender: nil)
} else {
NSUserDefaults.standardUserDefaults().setValue(1, forKey: "editProfile")
}
Any help would e appreciated.