IOS app in swift 3 not navigating to further viewcontrollers - ios

I am doing project on secured authentication....when i try to register my email id and password it is not going to next viewcontroller...when i run my code it is working well and not showing any errors but i am not getting output...here is my code
#IBAction func signInButtonTapped(_ sender: UIButton) {
// TODO: Do some form validation on the email and password
if let email = emailTextField.text, let pass = passwordTextField.text {
// Check if it's sign in or register
if isSignIn {
// Sign in the user with Firebase
FIRAuth.auth()?.signIn(withEmail: email, password: pass, completion: { (user, error) in
// Check that user isn't nil
if let u = user {
// User is found, go to home screen
self.performSegue(withIdentifier: "goToHome", sender: self)
}
else {
// Error: check error and show message
self.displayAlertMessage(messageToDisplay: "Password didn't match");
}
})
}
else {
// Register the user with Firebase
FIRAuth.auth()?.createUser(withEmail: email, password: pass, completion: { (user, error) in
// Check that user isn't nil
if let u = user {
// User is found, go to home screen
self.performSegue(withIdentifier: "goToEnroll", sender: self)
}
else {
// Error: check error and show message
}
})
}
}

Please check the connection in Storyboard, make sure that the segue name of link between Current VC -> Home VC is: "goToHome"
Check the same for Enroll VC

Check here if the idenfier is same as you have given in your story board.
Note: Please check first that the identifier you have mentioned here is same as your storyboard one.

Related

How to solve the problem with Firebase listener, which open everywhere?

I have some simple App, which have auth.
nearest code check if you already entered:
func signingManager(){
Auth.auth().addStateDidChangeListener { [weak self] (auth, user) in
guard let self = self else {return}
if user != nil {
self.showNextVC()
print("You are already entered")
}
}
}
It's works when you first open the app and if you entered func "showNextVC" will open next VC.
In the same time i have login button with code :
#IBAction func logInTapped(_ sender: UIButton) {
guard let email = emailTextField.text, let password = passwordTextField.text, email != "", password != "" else {
displayWarningLabel(withText: "info is incorrect")
return
}
Auth.auth().signIn(withEmail: email, password: password, completion: { [weak self] (user, error) in
if error != nil {
self?.displayWarningLabel(withText: "error occured")
return
}
if user != nil {
self?.showNextVC()
print("Congratulations, you have successfully logged in!")
}
self?.displayWarningLabel(withText: "no such user")
}
)}
Now about the problem: if I click the "login" button, the "signingManager ()" method and it's "showNextVC" are triggered first, and only then the "logInTapped" method itself and again "showNextVC".
As a result, I have 2 VCs and two messages:
"You are already entered" and
"Congratulations, you have successfully logged in!"
What am I doing wrong? Thanks!
Since you're listening for for auth state changes, you don't need to handle the self?.showNextVC() in the completion callback for signIn(withEmail:, password:). That code should only be present in the callback for addStateDidChangeListener.
Alternatively, you can:
Use the addStateDidChangeListener to initially detect whether the user is signed-in already.
Inside the callback for the state change:
Remove the listener by calling removeAuthStateDidChangeListener
Start the explicit sign-in flow, and call signIn(withEmail:, password:) like you're doing now.

Firebase Email already in use error

I am trying to login to my user after updating firebase, and after tracing the error, I get the following error:
Error Domain=FIRAuthErrorDomain Code=17007 "The email address is
already in use by another account."
UserInfo={NSLocalizedDescription=The email address is already in use
by another account., error_name=ERROR_EMAIL_ALREADY_IN_USE}
After looking it seems to be a because that firebase user is already in use, I am not sure how to fix this. I believe it is because I never signed out the user before closing app, but not am unable to login as any of my users.
Below is my code:
#IBAction func Login(sender: AnyObject) {
let email = self._Email.text!
let password = self._Password.text!
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
if error == nil {
//successfull login
print("Successful login****************************************")
//performs a segue to the next view controller
if user!.isEmailVerified{
//if the email is verified
let vc = self.storyboard!.instantiateViewController(withIdentifier: "ProfileView") as! ProfileView
self.present(vc, animated: true, completion: nil)
}
else {
print("email is not verified")
}
} else {
print("Some login error")
}
}
}
As ZassX pointed out, you're indeed using the signUp method of the Firebase iOS SDK, which is the createUserWithEmail. Use this method instead to signIn using email and password:
Auth.auth().signIn(withEmail: email, password: password) { (user, error) in
// ...
}
More info: https://firebase.google.com/docs/auth/ios/password-auth
You can check the list of your registered users in your Firebase Authentication Dashboard (https://console.firebase.google.com)
Also, it is good to print out the error description if you're having an error object. Like so:
print(error.localizedDescription).

Get uid after successfully signing in (Swift + Firebase)

I have created a very basic sign in app in swift to practice firebase. I've come up with this:
#IBAction func signInPressed(_ sender: UIButton) {
//Assigns and checks if the email and password aren't empty
if let inpt_email = emailField.text, let inpt_password = passwordField.text {
Auth.auth().signIn(withEmail: inpt_email, password: inpt_password, completion: { (user, error) in
//Checks if the user exists
if error != nil {
//ERROR: No user found
self.signInLabel.text = "Invalid User! Please Try Again"
} else {
//Sign Success
self.performSegue(withIdentifier: "toHome", sender: self)
}
})
}
} //End of signInPressed
// END: SIGN IN BUTTON
The //Sign Success part doesn't actually get any data at all, it just checks if the input matches any User that is registered in Firebase, and then segue to the next page. What I want to do is to:
Get the uid of the user which matches both the emailField and passwordField in the Firebase Auth.
Somewhat registers that uid as "Currently Signed In" in the app itself for future reference.
I tried reading the Firebase Documentation and all I got was this:
if Auth.auth().currentUser != nil {
// User is signed in.
// ...
} else {
// No user is signed in.
// ...
}
And this:
let user = Auth.auth().currentUser
if let user = user {
// The user's ID, unique to the Firebase project.
// Do NOT use this value to authenticate with your backend server,
// if you have one. Use getTokenWithCompletion:completion: instead.
let uid = user.uid
let email = user.email
let photoURL = user.photoURL
// ...
}
I'm new to Firebase so I basically don't understand how to use this, although I kind of get what it means, I just don't know what it's for or how to put it in action.
Thanks!
try this
if let user = user {
print(user.uid)
}
self.performSegue(withIdentifier: "toHome", sender: self)

Firebase segue authentication

Currently I'm working with a Firebase authentication and handled many errors like wrong username, password, empty fields etc and everything is working fine. However when I try to add a segue to the next page and use random email which is not exist in the database, Firebase auth didn't give me any errors and just pass the user to the next page. When I remove the segue and put random user it gives me an error that could not find such user which is what I'm trying to achieve with the segue. Please advise, what might be the problem?
AuthService file
func login(email: String, password: String, onComplete: Completion?) {
FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
self.handleFirebaseError(error: error! as NSError, onComplete: onComplete)
} else {
onComplete?(nil, user)
}
})
}
func handleFirebaseError(error: NSError, onComplete: Completion?) {
print(error.debugDescription)
if let errorCode = FIRAuthErrorCode(rawValue: error.code) {
switch (errorCode) {
case .errorCodeInvalidEmail:
onComplete?("Invalid email address", nil)
break
case .errorCodeWrongPassword:
onComplete?("Invalid password", nil)
break
case .errorCodeUserNotFound:
onComplete?("Can't find user", nil)
break
default:
onComplete?("There was a problem authentication. Try again", nil)
}
}
}
ViewController
#IBAction func loginBtnTapped(_ sender: Any) {
if let email = emailField.text, let pass = passwordField.text , (email.characters.count > 0 && pass.characters.count > 0) {
AuthService.instance.login(email: email, password: pass, onComplete: { (errMsg, data) in
guard errMsg == nil else {
self.alert(title: "Error Authentication", errMsg: errMsg!)
return
}
})
} else {
self.alert(title: "Username and password required", errMsg: "You must enter both a username and a password")
}
}
hybridcattt is correct. I'm going to add a more specific answer. When using segues, make sure it the next screen is not directly connected from the button, otherwise it will fire as soon as you tap it, regardless of the result you're waiting for.
Connect your view controller instead to the next view controller, like so:
And then add an indentifier to that segue.
Finally, when you get what you're waiting for (e.g. successful logging in), then do the performSegue.
If you are creating a segue in a storyboard, it fires immediately and opens the next view controller. Login code you have is async, and storyboard doesn't wait for it.
It is very likely that loginBtnTapped method is not even called if you have a segue configured (try adding a breakpoint there)

How do I authenticate users in shoudPerformSegueWithIdentifier and Firebase?

I'm trying to create an authentication page in storyboard using IOS swift and Firebase. Here is my storyboardsegue declaration:
Then I'm using shouldPerformSegueWithIdentifier to authenticate it. However, I also what to log the user in Firebase so my code is like so:
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
if db.authData != nil {
return true
} else {
let email = emailTextField.text
let password = passwordTextField.text
db.authUser(email, password: password, withCompletionBlock: {
error, authData in
if error != nil {
print(error.description)
} else {
print("logged in")
}
})
return false
}
}
This code somewhat works but I would have to click the log in button twice because the first time logs in the user in Firebase, and the second time the db.authData is no longer nil because the user is already logged in so it returns true. I don't want to have to click twice to log in, I just want to click once. I can't just put return true or return false in the withCompletionBlock either because the block returns void. How do I make this work?
Using current implementation you can't achieve this feature. You have two ways to do this:
Make the db.authUser() synchronous and return it's result
Instead of connecting the login button segue to next screen, add an IBAction method and implement the method like
#IBAction func login(sender : AnyObject?)
{
let email = emailTextField.text
let password = passwordTextField.text
db.authUser(email, password: password, withCompletionBlock: {
error, authData in
if error != nil
{
print(error.description)
}
else
{
// Navigate to next screen
// Start perform segue here
}
})
}

Resources