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

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
}
})
}

Related

App crashes with Firebase Phone Auth

I hope that this question is not duplicate because I couldn't find any thing similar.
I have two view controllers:
NEWPhoneAuthViewController
NEWVerifyCodeViewController
NEWPhoneAuthViewController Code:
import UIKit
import Firebase
class NEWPhoneAuthViewController: UIViewController {
#IBOutlet weak var phoneTxtField: UITextField!
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.
}
#IBAction func submitPressed(_ sender: Any) {
let phoneNumber = phoneTxtField.text!
PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber, uiDelegate: nil, completion: { (verificationID, error) in
if let error = error {
debugPrint(error.localizedDescription)
return
}
guard let verificationID = verificationID else { return }
print("Verification ID")
print(verificationID)
let verifyScene = NEWVerifyCodeViewController()
verifyScene.verificationID = verificationID
self.performSegue(withIdentifier: "toCodefromPhoneAuth", sender: nil)
//self.navigationController?.pushViewController(verifyScene, animated: true)
})
}
}
and my NEWVerifyCodeViewController code is:
import UIKit
import Firebase
class NEWVerifyCodeViewController: UIViewController {
#IBOutlet weak var codeTxtField: UITextField!
var verificationID:String?
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.
}
#IBAction func verifyPressed(_ sender: Any) {
if let verificationCode = codeTxtField.text {
let credential = PhoneAuthProvider.provider().credential(withVerificationID: verificationID!, verificationCode: verificationCode)
Auth.auth().signIn(with: credential) { (user, error) in
if let error = error {
debugPrint(error.localizedDescription)
}else {
debugPrint("Verified successfully")
print("Navigating to SignUp")
//self.performSegue(withIdentifier: "toSignUpfromCode", sender: nil)
//let newSignUp = NEWSignUp()
//self.navigationController?.pushViewController(newSignUp, animated: true)
//self.performSegue(withIdentifier: "toSignUpFromPhone", sender: nil)
//Once you have verified your phone number kill the firebase session.
//try? Auth.auth().signOut()
}
}
}
}
}
Now the problem is: when I tap on verify button in NEWVerifyCodeViewController the App crashes,
NOTES:
I printed Verification ID and its not NULL.
I printed code that the user receives and its not NULL.
So I'm not sure why that happens, and my console doesn't show any error after the tap except these:
So I made a small tweak that made my project work.
I changed this part in NEWPhoneAuthViewController :
let verifyScene = NEWVerifyCodeViewController()
verifyScene.verificationID = verificationID
to:
first created a global variable called: gVerificationID and set it to:
gVerificationID = verificationID
Thats it, not sure if thats the best practice and not sure why the first code didn't work but this is how I fixed it.

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
}

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

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

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")
})
})
}

My code for NSUserDefaults is not working

I am very new to swift. And need your help!
I want that, when the user logs in for the second time , the app should directly take it to the next view controller named CoreView. It should not ask for details, but I don't know why its not working. And it's asking for details everytime the app is launched. Please check the below code. I am not getting any sort of error too. Unless and until the app is killed or logged out, the user should be able to log in directly .
func pref_write()
{
// To write the data to NSUserDefaults
let prefs = NSUserDefaults.standardUserDefaults() // make a reference
print("OTP:\(OTP)")
// Adding values. Creating objects in prefs
prefs.setObject(OTP, forKey: "OTP")
print("check_OTP:\(check_OTP)")
prefs.setObject(U_ID, forKey: "U_ID")
print("Check_U_ID:\(check_U_ID)")
prefs.synchronize()
self.performSegueWithIdentifier("ContinueToCoreView", sender: self)
}
And in the viewDidLoad function:
override func viewDidLoad()
{
super.viewDidLoad()
//Read the data
self.performSegueWithIdentifier("ContinueToCoreView", sender: self)
pref_write()
let prefs = NSUserDefaults.standardUserDefaults()
check_OTP = prefs.objectForKey("OTP")!
check_U_ID = prefs.objectForKey("U_ID")!
prefs.objectForKey("U_ID")
print("prefs:\(prefs)")
prefs.synchronize()
}
Thanks!
Create a class as
class User_Details : NSObject
{
var user_id : String?
var user_otp : String?
var otp_verified : Bool?
init(u_id:String, otp:String?, verified:Bool)
{
super.init()
self.user_id = u_id
self.otp_verified = verified
self.user_otp = otp
}
}
In AppDelegate,
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
navController = self.window?.rootViewController as? UINavigationController
if self.checkIfUserLoggedIn()
{
let user_details = NSUserDefaults.standardUserDefaults().objectForKey("user_details") as! User_Details
self.moveToNextScreen(user_details)
}
return true
}
//AppDelegate Class or in the class which is globally accessible
func pref_write_user(user_details : User_Details)
{
let prefs = NSUserDefaults.standardUserDefaults()
prefs.setObject(user_details, forKey: "user_details")
prefs.setBool(true, forKey: "is_user_login")
//After saving the OTP for current user, check for otp verified, move to OTP Screen
self.moveToNextScreen(user_details)
}
func moveToNextScreen(user_details : User_Details)
{
if user_details.otp_verified == false
{
// Move to OTP screen
let viewController = self.navController?.storyboard?.instantiateViewControllerWithIdentifier("otpScreen")
self.navController?.pushViewController(viewController!, animated: false)
}
else // Move to Home Screen
{
let viewController = self.navController?.storyboard?.instantiateViewControllerWithIdentifier("homeScreen")
self.navController?.pushViewController(viewController!, animated: false)
}
}
func logoutUser()
{
let prefs = NSUserDefaults.standardUserDefaults()
prefs.setObject(nil, forKey: "user_details")
prefs.setBool(false, forKey: "is_user_login")
}
func checkIfUserLoggedIn() -> Bool
{
let prefs = NSUserDefaults.standardUserDefaults()
if prefs.boolForKey("is_user_login")
{
if let _ = prefs.objectForKey("user_details")
{
return true
}
else
{
//User details not found for some reason, so setting the inital values and return false
self.logoutUser()
}
}
return false
}
Login Class :
Call the API for login by providing the basic credential, get the user_id and user_otp, save them to NSUserDefaults
func requestLoginToServer()
{
//Perform basic server action
....
//In Success Block write this
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
// pass the values as return by the server
let user_details = User_Details(u_id: "123", otp: "1234", verified: false)
appDel.pref_write_user(user_details)
appDel.moveToNextScreen(user_details)
}
Please try this way. I just rearranged your code.
First it will check the login credentials with in the didload method of initial view controller. If it not there it will call the method pref_write() . Please make sure that the values used in pref_write() method are not nil
override func viewDidLoad()
{
super.viewDidLoad()
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
// You can give conditions for your need like if(prefs.valueForKey("U_ID") != nil))
// It will check the user defaults whether you already login
if(prefs.valueForKey("OTP") != nil) {
self.performSegueWithIdentifier("ContinueToCoreView", sender: self)
}
else{
pref_write()
}
}
// Make sure the Values are not nil
func pref_write()
{
// To write the data to NSUserDefaults
let prefs = NSUserDefaults.standardUserDefaults() // make a reference
print("OTP:\(OTP)")
// Adding values. Creating objects in prefs
prefs.setObject(OTP, forKey: "OTP")
print("check_OTP:\(check_OTP)")
prefs.setObject(U_ID, forKey: "U_ID")
print("Check_U_ID:\(check_U_ID)")
prefs.synchronize()
self.performSegueWithIdentifier("ContinueToCoreView", sender: self)
}
Hope its working...

Resources