Redirect the user to a specific page after signIn - ios

Main issue is checking if user has a child in the Firebase database so that I know if he is signing up or logging in.
Part 1: Part 1 (Child Database (this works) and making that a user default (I'm not sure how to check it that worked)
Part 2: in different .Swift file (Check if the User Default (aka Education Child) exists. I have pretty much nothing, except I know it must go into viewDidAppear
Part 1
#IBAction func SubmitPressed(_ sender: Any) {
let databaseRef = Database.database().reference()
let uid = Auth.auth().currentUser!.uid
databaseRef.child("Education").child(uid).setValue(self.Education.text!)
UserDefaults.standard.set("Education", forKey: "Education")
Part 2
func viewDidAppear(_ animated: String) {
??????
}
No error for part 1, though not sure if it created the user default. For part 2, I have tried a bunch of stuff, but hasn't worked.
Here is the updated code after first answer:
import Foundation
import UIKit
import SwiftKeychainWrapper
import Firebase
import CoreFoundation
import AVFoundation
import FirebaseDatabase
var educationCache : String {
get {
return (UserDefaults.standard.string(forKey: "Education")!)
} set {
UserDefaults.standard.set(newValue, forKey: "Education")
}
}
relavant part of education/personal info enter page
#IBAction func SubmitPressed(_ sender: Any) {
let databaseRef = Database.database().reference()
let uid = Auth.auth().currentUser!.uid
databaseRef.child("Education").child(uid).setValue(self.Education.text!)
// The following line will save it in userDefault itself. And you dont have to call the whole UserDefault Everywhere
educationCache = "Education"
self.performSegue(withIdentifier: "tohome", sender: nil)
}
homepage
import Foundation
import UIKit
import SwiftKeychainWrapper
import Firebase
import CoreFoundation
import AVFoundation
import FirebaseDatabase
class homepage:UITableViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if educationCache.count < 0 {
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
override func viewDidLoad() {
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Sign Out", style: .plain, target: self, action: #selector(signOut))
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#objc func signOut (_sender: AnyObject) {
KeychainWrapper.standard.removeObject(forKey: "uid")
do {
try Auth.auth().signOut()
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
}
dismiss(animated: true, completion: nil)
}
}

You dont want to check the condition is the viewController where you are performing specific actions. Also checking the userDefaults everytime is just putting extra views in heirarchy. Firebase provides .addStateDidChangeListener function to keep a check of it. Add the following code to your delegate. It will automatically switch between the users if there are any or not.
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
observeUser()
return true
}
func observeUser(){
Auth.auth().addStateDidChangeListener { (auth, user) in
if (user != nil) {
// If the user is not nil. Perform this block
self.showInitController(with identifier: "<add_your_storyboard_reusableID_for_homepage>", animated: false)
// The storyboard Id belongs to the HOMEPAGE/FEED, the view where user goes on signIn
} else {
//If there is no user. This block will perform
self.showInitController(with identifier: "<add_your_storyboard_reusableID_for_loginpage>", animated: false)
// The storyboard Id belongs to the SIGNUP PAGE, the view where user goes on signIn
}
}
}
func showInitController(with identifier: String, animated: Bool = false) {
DispatchQueue.main.async {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: identifier)
var topRootViewController: UIViewController = (UIApplication.shared.keyWindow?.rootViewController)!
while((topRootViewController.presentedViewController) != nil){
topRootViewController = topRootViewController.presentedViewController!
}
topRootViewController.present(vc, animated: animated, completion: nil)
}
}
In your swift file one. do the following and never look back. You can automatically redirect to view if you applied the other functions.
#IBAction func SubmitPressed(_ sender: Any) {
let databaseRef = Database.database().reference()
let uid = Auth.auth().currentUser!.uid
databaseRef.child("Education").child(uid).setValue(self.Education.text!)
self.performSegue(withIdentifier: "tohome", sender: nil)
}
In the second view dont bother to do anything anywhere. Just leave it, if nothing in that view is required again.

Related

Refresh Storyboard viewcontroller using swift iOS

Im having button in all viewcontrollers to change language
LanguageViewController.swift
class LanguageViewController: UIViewController {
#IBAction func actionChange(_ sender: Any) {
L102Language.currentAppleLanguage()
L102Language.setAppleLAnguageTo(lang: "en")
// below code to refresh storyboard
self.viewDidLoad()
}
}
L102Language.swift
class func currentAppleLanguage() -> String{
let userdef = UserDefaults.standard
let langArray = userdef.object(forKey: APPLE_LANGUAGE_KEY) as! NSArray
let current = langArray.firstObject as! String
let endIndex = current.startIndex
let currentWithoutLocale = current.substring(to: current.index(endIndex, offsetBy: 2))
return currentWithoutLocale
}
/// set #lang to be the first in Applelanguages list
class func setAppleLAnguageTo(lang: String) {
let userdef = UserDefaults.standard
userdef.set([lang,currentAppleLanguage()], forKey: APPLE_LANGUAGE_KEY)
userdef.synchronize()
}
I inherited LanguageViewController in all my FirstViewCOntroller, SecondController as below
class FirstViewController: LanguageViewController {
}
class SecondController: LanguageViewController {
}
If I call self.viewDidLoad() it fails to change language from view defined in storyboard. How to reload storyboard, so that the language should change in all viewcontroller,if any button from any viewcontroller is clicked? Thanks!
You can use NotificationCenter for reloading the view controllers content, this will also reload the content of view controllers that are not visible.
extension Notification.Name {
static let didChangeLanguage = Notification.Name("didChangeLanguage")
}
override func viewDidLoad() {
//Add a listener
NotificationCenter.default.addObserver(self, selector: #selector(onDidChangeLanguage(_:)), name: .didChangeLanguage, object: nil)
}
#IBAction func actionChange(_ sender: Any) {
L102Language.currentAppleLanguage()
L102Language.setAppleLAnguageTo(lang: "en")
// Notify about the change.
NotificationCenter.default.post(name: .didChangeLanguage, object: self, userInfo: nil)
}
#objc func onDidChangeLanguage(_ notification:Notification) {
// reload content using selected language.
}
Correct me if I'm wrong. but I think you don't need to reload all view controllers. you just need to update them when they get displayed, view controllers are behind the presented one are not visible for the user.
for doing that you can do something like this:
var currentLanguage = ""
override func viewDidLoad() {
currentLanguage = currentAppleLanguage()
loadContentForLanguage(currentLanguage)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// this will be executed every time this sceen gets display
if currentLanguage != currentAppleLanguage() {
currentLanguage = currentAppleLanguage()
loadContentForLanguage(currentLanguage)
}
}
func loadContentForLanguage(_ currentLanguage: String) {
//here it goes whatever you currently have in viewDidLoad
}
My apologies if this does not compile, my swift is really rusty.

How to force new user or who just register have to fill the form first (FirebaseUI in IOS)

I'm using FirebaseUI as registration system, and now user can login by 2 way (facebook and phone number) but now problem is i want new user or first time login must fill the form before go to MainViewController. on the other hand, old user who ever fill the form will go to MainViewController without force to fill the form again.
Now I'm using Xcode 10.2 and FirebaseUI 6.2.1
Now I'm using Xcode 10.2 and FirebaseUI 6.2.1
import UIKit
import Firebase
import FirebaseUI
class UserLoginViewController: UIViewController, FUIAuthDelegate {
override func viewDidAppear(_ animated: Bool){
super.viewDidAppear(animated)
if Auth.auth().currentUser != nil {
//Old user go to segue withIdentifier "GoMain"
self.performSegue(withIdentifier: "GoMain", sender: nil)
//First time login go to segue withIdentifier "FillForm"
}
let authUI = FUIAuth.defaultAuthUI()
guard authUI != nil else {
return
}
authUI?.delegate = self
let providers: [FUIAuthProvider] = [
FUIFacebookAuth(),
FUIPhoneAuth(authUI:FUIAuth.defaultAuthUI()!),
]
authUI?.providers = providers
let authViewController = authUI!.authViewController()
authViewController.isNavigationBarHidden = true
present(authViewController, animated: true, completion: nil)
}
}
extension UserLoginViewController {
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {
if error != nil {
return
}
}
}

firebase authentication ios use of unresolved identifier 'handle'

I'm trying to follow this tutorial for Firebase authentication.. I kinda just followed the code but keep having the Use of unresolved identifier 'handle' error.
Code:
import UIKit
import Firebase
import FirebaseAuth
class SignInViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
handle = Auth.auth().addStateDidChangeListener { (auth, user) in // ERROR HERE
// ...
}
}
override func viewWillDisappear(_ animated: Bool) {
Auth.auth().removeStateDidChangeListener(handle!) // ERROR HERE
}
}
Any clue what I should do? Thanks!
#IBAction func createAccount(_ sender: Any) {
let emailTextD = self.emailText.text!
let passwordTextD = self.passwordText.text
Auth.auth().createUser(withEmail: emailTextD, password: passwordTextD!) { (authResult, error) in
// ...
}
}
Add the variable declaration into the class like this:
var handle: AuthStateDidChangeListenerHandle?

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.

App works in simulator but not on device

My app runs fine on simulator but when I run on device it hangs on the first view. It doesn't call anything in viewDidLoad or viewDidAppear. Running swift 3, iOS 10, device is a 6S updated to iOS 10.
import UIKit
import Firebase
import SwiftKeychainWrapper
class FirstVC: UIViewController {
override func viewDidLoad() {
}
override func viewDidAppear(_ animated: Bool) {
// MARK: Checks if you have an account and never logged out
if let userId = KeychainWrapper.defaultKeychainWrapper().stringForKey(KEY_UID) {
DataService.ds.REF_USERS.child(userId).observeSingleEvent(of: .value, with: { (FIRDataSnapshot) in
guard let dict = FIRDataSnapshot.value as? NSDictionary, let setup = dict["setup"] as? Bool else {
self.performSegue(withIdentifier: "firstToDemo", sender: nil)
return
}
if setup {
self.performSegue(withIdentifier: "firstToPollBar", sender: nil)
} else {
self.performSegue(withIdentifier: "firstToDemo", sender: nil)
}
})
} else {
self.performSegue(withIdentifier: "firstToLogin", sender: nil)
}
}
}

Resources