Swift - Login with FireBase - Can't retrieve user data after login - ios

Firebase Authentication - Can't retrieve user data after login.
I'm trying to retrieve the users email after sign in (logincontroller) and display it in a UILABEL on another controller (maincontroller). When you create a user or use an existing one, it works fine the first time after launching the app, but when you sign out and try to use another email it does not work.
I have two view controllers:
import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase
class LoginViewController: UIViewController {
var ref: FIRDatabaseReference!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func signInButton(sender: AnyObject) {
FIRAuth.auth()?.signInWithEmail(emailTextField.text! , password: passwordTextField.text!, completion: { (user, error) in
if error != nil {
print(error!.localizedDescription)
}
})
self.performSegueWithIdentifier("MainViewSegue", sender: self)
}
#IBAction func createAccountButton(sender: AnyObject) {
FIRAuth.auth()?.createUserWithEmail(emailTextField.text!, password: passwordTextField.text!, completion: { (user, error) in
if error != nil {
print(error!.localizedDescription)
} else {
print("User Created.")
let userID: String = user!.uid
let userEmail:String = self.emailTextField.text!
self.ref.child("users").child(userID).setValue(["email": userEmail])
}
})
}
}
and:
import Foundation
import UIKit
import Firebase
import FirebaseDatabase
class MainViewController: UIViewController {
var ref: FIRDatabaseReference!
var refHandle: UInt!
#IBOutlet weak var userEmailLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference()
refHandle = ref.observeEventType(FIRDataEventType.Value, withBlock: { (snapshot) in
let dataDict = snapshot.value as! [String: AnyObject]
print((dataDict))
})
let userID: String = (FIRAuth.auth()?.currentUser?.uid)!
ref.child("users").child(userID).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
let userEmail = snapshot.value!["email"] as! String
self.userEmailLabel.text = userEmail
})
}
#IBAction func signOutButton(sender: AnyObject) {
try! FIRAuth.auth()!.signOut()
if let storyboard = self.storyboard {
let viewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController")
self.presentViewController(viewController, animated: false, completion: nil)
}
}
}
This is where I get the error EXC_BAD_INSTRUCTION:
let userID: String = (FIRAuth.auth()?.currentUser?.uid)!

CMD+CLICK on signInWithEmail in FIRAuth.auth()?.signInWithEmail(emailT... and you will be directed to its documentation, above that function in its documentation you will see :-
#param completion Optionally; a block which is invoked when the sign in flow finishes, or is
canceled. Invoked asynchronously on the main thread in the future.
which means your completionBlock is invoked when your user is either signed in or signInWithEmail function has given some error.But in your case self.performSegueWithIdentifier("MainViewSegue", sender: self) will get called even before your completionBlock: is called.
Try this:-
#IBAction func signInButton(sender: AnyObject) {
FIRAuth.auth()?.signInWithEmail(emailTextField.text! , password: passwordTextField.text!, completion: { (user, error) in
if error != nil {
print(error!.localizedDescription)
}else if error == nil{
self.performSegueWithIdentifier("MainViewSegue", sender: self)
}
})
}
Also replace :-
let userID: String = (FIRAuth.auth()?.currentUser?.uid)!
with
let userID: String = FIRAuth.auth()!.currentUser!.uid
No need to forcefully unwrap an optional value which you know does exist

Related

How to add a user with setValue from Firebase Reading and writing data in ios

I am a newbie in Swift and I am learning by building a social media application.
I am struck at trying to implement self.ref.child("users").child(user.uid).setValue(["username": username]) in my code (from https://firebase.google.com/docs/database/ios/read-and-write).
I have been following the instructions of Kasey Schlaudt and at this point of the tutorial https://youtu.be/GrRggN41VF0?t=619 he tried to add a user with setValue as shown in the Firebase documentation I have linked. The errors I get in the line self.ref.child("users").child(user.uid).setValue(["username": username]) are
Use of unresolved identifier 'user' and Use of unresolved identifier 'username'.
My code so far (with some little changes from the original code in the video in my signInPress function) is
import UIKit
import Firebase
import SwiftKeychainWrapper
class ViewController: UIViewController {
#IBOutlet weak var UserImageView: UIButton!
#IBOutlet weak var usernameField: UITextField!
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
override func viewDidLoad()
{
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool)
{
if let _ : Bool = KeychainWrapper.standard.string(forKey: "uid") != nil
{
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
func storeUserData(userID: String)
{
//---------------------------problematic line---------------------------
//from https://firebase.google.com/docs/database/ios/read-and-write
//from https://youtu.be/GrRggN41VF0?t=619
self.ref.child("users").child(user.uid).setValue(["username": username])
([
"username": usernameField.text
])
}
#IBAction func signInPress(_ sender: Any)
{
//this way you make sure there is a property inside emailField.text and you have a variable you can easily use
if let email = emailField.text, let password = passwordField.text
{
Auth.auth().signIn(withEmail: email, password: password)
{ (result, error) in
if error != nil && self.usernameField.text!.isEmpty && self.UserImageView.image != nil
{
Auth.auth().createUser(withEmail: email, password: password)
{ (result, error) in
self.storeUserData(userID: (result?.user.uid)!)
KeychainWrapper.standard.set((result?.user.uid)!, forKey: "KEY_UID")
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
} else
{
KeychainWrapper.standard.set((result?.user.uid)!, forKey: "KEY_UID")
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
}
}
}
I would very much appreciate any indication as to why the error does not occur for Kasey and what I might need to change to do the same process.
Thank you in advance !
You're actually pretty close, more of a typo issue. See that your storeUserData function is expecting a string called userID? That's what's needed in the line to store that data instead of user.uid
func storeUserData(userID: String) {
let username = self.usernameField.text
self.ref.child("users").child(userID).setValue(["username": username])
here ^^^^^^ userID instead of user.uid
}

User variable is nil when creating a user with Firebase

I am following a tutorial and cannot seem to register my user as the user variable in the Firebase .createUser method appears to be nil. Therefore, when I unwrap it, I get an error.
I have read through a lot of the documentation as well as checked many other questions similar to mine but nothing seems to work
import UIKit
import Firebase
import SwiftKeychainWrapper
class ViewController: UIViewController {
#IBOutlet weak var userImgView: UIImageView!
#IBOutlet weak var usernameField: UITextField!
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
var imagePicker: UIImagePickerController!
var selectedImage: UIImage!
override func viewDidLoad() {
super.viewDidLoad()
imagePicker = UIImagePickerController()
imagePicker.allowsEditing = true
imagePicker.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
if let _ = KeychainWrapper.standard.string(forKey: "uid") {
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setupUser(userUid: String) {
if let imageData = self.userImgView.image!.jpegData(compressionQuality: 0.2) {
let imgUid = NSUUID().uuidString
let metaData = StorageMetadata()
Storage.storage().reference().child(imgUid).putData(imageData, metadata: metaData) { (metadata, error) in
let downloadURL = metadata
let userData = [
"username": self.usernameField.text!,
"userImg": downloadURL!
] as [String : Any]
Database.database().reference().child("users").child(userUid).setValue(userData)
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
}
#IBAction func signInPressed(_ sender: Any) {
if let email = emailField.text, let password = passwordField.text {
Auth.auth().signIn(withEmail: email, password: password) { user, error in
if error != nil && !(self.usernameField.text?.isEmpty)! {
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
self.performSegue(withIdentifier: "toFeed", sender: nil)
let userID = (user?.user.uid)!
self.setupUser(userUid: userID)
KeychainWrapper.standard.set(userID, forKey: "uid")
}
} else {
if let userID = (user?.user.uid) {
KeychainWrapper.standard.set((userID), forKey: "uid")
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
}
}
}
#IBAction func getPhoto (_ sender: AnyObject) {
present(imagePicker, animated: true, completion: nil)
}
}
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
internal func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[.originalImage] as? UIImage {
userImgView.image = image
} else {
print("image wasnt selected")
}
imagePicker.dismiss(animated: true, completion: nil)
}
}
The error I am getting is one the "let userID = (user?.user.uid)!". It is
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
The completion block for createUser(withEmail:,password:) gets called with either a AuthResult.user or an error. That why, as Joshua commented, you should check if error is nil before accessing any of the user properties.
From the auth quickstart for Swift:
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
strongSelf.hideSpinner {
guard let user = authResult?.user, error == nil else {
strongSelf.showMessagePrompt(error!.localizedDescription)
return
}
print("\(user.email!) created")
strongSelf.navigationController?.popViewController(animated: true)
}
}

Passing FBSDK login manager result between view controllers

I can't transfer the login manager result between view controllers,
The segue is associated to the button and its identifier is s1.
My setup is correct.The program is crashing with green breakpoints.
here is my code:
for the first VC:
import FBSDKLoginKit
class ViewController: UIViewController {
var user_name: String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let fbLoginManager = FBSDKLoginManager()
fbLoginManager.logIn(withReadPermissions: ["public_profile", "email"], from: self) { (result, error) in
if let error = error {
print("Failed to login: \(error.localizedDescription)")
return
}
guard let accessToken = FBSDKAccessToken.current() else {
print("Failed to get access token")
return
}
let credential = FIRFacebookAuthProvider.credential(withAccessToken: accessToken.tokenString)
FBSDKGraphRequest(graphPath: "/me", parameters: ["fields" : "email, id, locale"])
.start(completionHandler: { (connection, result, error) in
guard let result = result as? NSDictionary,
let user_name = result["user_name"] as? String,
else {
return
}
if(segue.identifier == "s1"){
if let v = segue.destination as? Re {
v.uname=user_name ?? ""
//v.uname = usr.text ?? ""
}
}
})
// Perform login by calling Firebase APIs
FIRAuth.auth()?.signIn(with: credential, completion: { (user, error) in
if let error = error {
print("Login error: \(error.localizedDescription)")
let alertController = UIAlertController(title: "Login Error", message: error.localizedDescription, preferredStyle: .alert)
return
}
})
}
}
}
And for Re,the next VC:
class Re: UIViewController {
var uname: String?
#IBOutlet weak var l1: UILabel!
var userfb: String?
override func viewDidLoad() {
super.viewDidLoad()
l1.text=uname
// Do any additional setup after loading the view.
}
}
You need to use instance variable which you have declared at top as below.
Now you have create new user_name and use another user_name
guard let result = result as? NSDictionary,
user_name = result["user_name"] as? String,// make change here
else {
return
}

How to display firstname in UILabel?I am developing IOS app with Firebase and Swift

I am practicing IOS app using Firebase and Swift.
This is an basic app where a user logs in with username and password. User can Signup, login, and logout. For this I have created 3 viewcontrollers.One for userlogin, 2nd to signup, and third to display user's firstname and picture.
I have created a viewcontroller "loginPageViewController" to display user's firstname and picture. I am trying to display firstname in "userFirstName" label. But I am unable to do. Error message is attached in screenshot.
Supplements:
Error is occured here
Storyboard
Swift Code:
import UIKit
import Firebase
import FirebaseAuth
class loginPageViewController: ViewController {
#IBOutlet weak var userFirstName: UILabel!
#IBOutlet weak var userImage: UIImageView!
let userID = FIRAuth.auth()?.currentUser?.uid
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let userID = (FIRAuth.auth()?.currentUser?.uid)!
ref.child("expatsappmembers").child(userID).observeSingleEventOfType(
.Value, withBlock: { (snapshot) in
let firstName = snapshot.value!["firstName"] as! String
self.userFirstName.text = firstName
})
}
#IBAction func LogoutButtoninLoginPage(sender: AnyObject) {
if FIRAuth.auth()?.currentUser != nil{ //there is a user signed in
do{
try FIRAuth.auth()?.signOut()
if FIRAuth.auth()?.currentUser == nil{
let loginVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("InitialView") as? ViewController
self.presentViewController(loginVC!, animated: true, completion: nil)
}
}catch let signOutError as NSError{
print ("Erros signing out: %#", signOutError)
}
}
}
}
"
Any suggestions will be a great help for me.
Thank you in advance.
Before the user have logged in the FIRAuth.auth()?.currentUser?.uid is nil. The problem is that you force unwrap it (!).
You should first check that the user is logged in, and only then continue with your logic.
I would start with this:
if let userID = FIRAuth.auth()?.currentUser?.uid {
ref.child("expatsappmembers").child(userID).observeSingleEventOfType(
.Value, withBlock: { (snapshot) in
if let firstName = snapshot.value?["firstName"] as? String {
self.userFirstName.text = firstName
}
})
}

Error while registering a new user on Firebase

When I try to register a new user, I get an error saying value of type 'FIRDatabaseReference' has no member 'createuser'. See image below.
FIRAuth.auth()?.createUserWithEmail(<email: String>, password: <String>, completion: <FIRAuthResultCallback?(FIRUser?, NSError?) -> Void#>)
Here is a screenshot of how the code looks like picture of the code and the imageview:
Try this code it is working absolutely fine for me
//
// ViewController.swift
// FirebaseExample
//
// Created by Belal Khan on 03/10/16.
// Copyright © 2016 Belal Khan. All rights reserved.
//
import UIKit
//importing firebase
import Firebase
class ViewController: UIViewController {
//Textfields for email and password
#IBOutlet weak var textFieldEmail: UITextField!
#IBOutlet weak var textFieldPassword: UITextField!
//label for displaying message
#IBOutlet weak var labelMessage: UILabel!
//button for registration
#IBAction func buttonRegister(sender: UIButton) {
//do the registration operation here
//first take the email and password from the views
let email = textFieldEmail.text
let password = textFieldPassword.text
FIRAuth.auth()?.createUserWithEmail(email!, password: password!, completion: { (user: FIRUser?, error) in
if error == nil {
self.labelMessage.text = "You are successfully registered"
}else{
self.labelMessage.text = "Registration Failed.. Please Try Again"
}
})
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//initialising firebase
FIRApp.configure()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Source: swift firebase tutorial
The code does not match. ref.createUser is different from FIRAuth.auth()?.createUserWithEmail
This is a working piece of code I tried a few days ago in XCode 7.3.1 I am not sure which version of XCode you are using. However, there's no pre-defined function as you tried!
func buttonHandleRegister() {
guard let email = emailTextField.text, password = passwordTextField.text, name = nameTextField.text else {
print("Form is not valid")
return
}
FIRAuth.auth()?.createUserWithEmail(email, password: password, completion: { (user: FIRUser?, error) in
if error != nil {
print("Error")
return
}
guard let uid = user?.uid else {
return
}
//successfully logged in
let ref = FIRDatabase.database().referenceFromURL("https://some-random-name.firebaseio.com/")
let usersReference = ref.child("users").child(uid)
let values = ["name" : name, "email": email, "password": password]
usersReference.updateChildValues(values, withCompletionBlock: { (err, ref)
in
if err != nil {
print(err)
return
}
print("Saved user succesfully")
})
})
}

Resources