Firebase Auth, acquiring textfield value from different class - ios

I am using Firebase email authentication in my app, I have 2 different view controllers for the sign up process, first view controller asks for the email for firebase and the second view controller asks for the password. How can I set it up for the firebase code?
if let phoneEmail = phoneEmailTextField.text, let createdpassword = createdPasswordTextField {
Auth.auth().createUser(withEmail: phoneEmail, password: createdpassword, completion: { (user, error) in
I have the textfield "phoneEmailTextField" in the first view controller (class 1) and the textfield "createdPasswordTextField" in the second view controller(class 2). How can I link the textfield "createdPasswordTextField" from the second view controller (class 2) back to the first view controller (class 1) in order to execute the Firebase function?

Use segue for passing mail textfield's data from first view controller to the second.Shortly,search how segue,navigation controller pushing works.

Something like that;
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
if let secondViewController = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController {
secondViewController.emailTextFieldString = emailTextField.text!
self.navigationController?.pushViewController(secondViewController, animated: true)
}

Related

How to move login page when session expired

I have multiple screens and api's, if session expired each api get session expired message. Based in that I'm moving from current page to login page.
My code :
//If session expaired move to login page
if message == "Session Expired" {
//Session Expired
DispatchQueue.main.async {
let lpc = self.storyboard?.instantiateViewController(withIdentifier: "LVC")
//Set the user login key false
UserDefaults.standard.set(false, forKey: "isUserLoggedIn")
//Clear user defaults
SharedClass.sharedInstance.clearDataFromUserDefaults()
self.navigationController?.pushViewController(lpc!, animated: false)
}
}
Here I'm using ** pushViewController** to navigate back. Every thing working fine, but when i'm in Nth VC is session expired it's navigating N times to login page. Means if I'm navigating from 1st VC to 2nd VC, 2nd VC to 33rd VC, 3rd VC to 4th, is session expired in 4th VC it's navigating to login page around 3times. How to resolve this issue....
You can try this
let vc = self.storyboard?.instantiateViewController(withIdentifier: "LVC")
self.navigationController?.setViewControllers([vc], animated: true)
Since you didn't provide your full code so I am not sure why that issue happens. However, here are 2 solutions to achieve your requirement.
First implementation: Image for 1st flow
If the user logged in:
navigationController?.viewControllers = [loggedInVC]
If the user doesn't login yet or when he/she logout:
navigationController?.viewControllers = [logInVC]
2nd implementation: Image for 2nd flow
LoginVC is the root view controller and acts as a loading screen, and only show the login form when the session is invalid. With this implementation, every time the session is invalid. You can call:
navigationController?.popToRootViewController(animated: true)
to navigate the user back to the login screen.
First create the global variable to access the AppDelegate, because we are putting redirection function here.
let appDelegate = UIApplication.shared.delegate as! AppDelegate
Now put below function in AppDelegate to set login screen whenever your session is expired.
func configureWindow(_ viewController: UIViewController) {
if let window = window {
window.rootViewController = viewController
window.makeKeyAndVisible()
}
}
now set your login UIViewController as like below.
let loginVC = LoginViewController()
appDelegate.configureWindow(loginVC)
use the following:
self.navigationController?.popToRootViewController(animated: false)
if login is not root,then you can use the following:
if let controllers = self.navigationController?.viewControllers, controllers.count > 0{
for vc in controllers{
if vc is LoginViewController{
self.navigationController?.popToViewController(vc, animated: false)
}
}
}
I don't know is this right or wrong. But i'm getting one more issue
1) First i cleared all navigations from navigation stack
2) Then i made my LoginVC as Root VC
3) Finally i called popToRootViewController
//If session expaired move to login page
if message == "Session Expired" {
DispatchQueue.main.async {
//Check navigation stacks
let navigationArray = self.navigationController?.viewControllers //To get all UIViewController stack as Array
print(navigationArray!)//Prints navigation stacks
//Remove all
self.navigationController!.viewControllers.removeAll()
//Check navigation stacks
let navigationArray2 = self.navigationController?.viewControllers //To get all UIViewController stack as Array
print(navigationArray2 as Any)//Prints nill
//Check whether the user logined or not
UserDefaults.standard.set(false, forKey: "isUserLoggedIn")
//Clear user defaults
SharedClass.sharedInstance.clearDataFromUserDefaults()
let lvc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LVC") as! LoginViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = lvc
}
}
//Call alert function
self.showAlert(title: "", msg: message)
I don't know is this right or wrong. But i'm getting one more issue
Warning: Attempt to present <UIAlertController: 0x7fb840800600> on <******: 0x7fb840069800> whose view is not in the window hierarchy!

passing data from 2 view controllers without segue

I have a mainviewcontroller and a popup view controller which opens without a segue.
the popup viewcontroller recive data from Firebase, and then i need to append this data to an array in the mainviewcontroller.
How can i do that?
(i tried to create a property of the popupviewcontroller in the mainviewcontroller, but in crashes the app)
this is the code that opens the popup:
#IBAction func showPopUp(_ sender: Any) {
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "sbPopUp") as! PopUpViewController
self.addChild(popOverVC)
popOverVC.view.frame = self.view.frame
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParent: self)
You need to connect the classes so that the popup class knows what to do with the data once it has been received. Here's a sample structure that works in a playground that you should be able to apply to your real classes.
class MainClass {
func showPopUp() {
let popOverVC = PopUpClass()
popOverVC.update = addToArray
popOverVC.receivedData()
}
func addToArray() {
print("Adding")
}
}
class PopUpClass {
var update: (()->())?
func receivedData() {
if let updateFunction = update {
updateFunction()
}
}
}
let main = MainClass()
main.showPopUp()
Or you could create a global variable so it can be accessed anywhere. ... It is better to pass data but I just thought it would be easier in this instance, so the variable can be accessed anywhere in your entire project.
if it is just a notification, you can show it in an alert, but if you don't want to use an alert my offer to present another view controller is not like this , try my code :
//if you have navigation controller ->
let vc = self.storyboard?.instantiateViewController(
withIdentifier: "storyboadrID") as! yourViewController
self.navigationController?.pushViewController(vc, animated: true)
//if you don't use navigation controller ->
let VC1 = self.storyboard!.instantiateViewController(withIdentifier: "storyboadrID") as! yourViewController
self.present(VC1, animated:true, completion: nil)
also if you want to pass any data or parameter to destination view controller you can put it like this before presenting your view controller :
VC1.textView.text = "test"

Change first viewController presented (main interface)

Hello i have done a page controller for my app.
This page controller will appear at the app launch if there isn't any "User" core data object on the device.
So want i want to do is :
When app launch, do a core data request that return all "User" objects in a array. (this part is ok)
If the array is empty the VC presented is the pageController else that's the normal on whose presented.
The pageController and the other controller are on different storyboards.
I have seen we can change the first storyboard in the app parameter, that's parameter is called main interface.
Actually main interface is the normal VC, so how can i present the page controller programmaticly in my didFinishLaunchingWithOptions() when my condition is true ?
Inside didFinishLaunchingWithOptions
// query coredata
if arr.isEmpty {
let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "pageID") as! PageController
self.window?.rootViewController = viewController
}
else {
let otherController = UIStoryboard(name: "Other", bundle: nil).instantiateViewController(withIdentifier: "otherID") as! OtherController
self.window?.rootViewController = otherController
}

How to show once an UIVIewController in swift

I’m making an app, and I need to show only one time the on boarding view controller, so when the user re enter the app the on boarding view controller doesn’t appear any more.
I guess the on boarding view controller is your initial view controller. Try this in app delegate
First put checkFunction() in didFinishLaunchingWithOptions then set the identity (eg. Home) for the view controller you want to go
func checkFunction() {
let acceptedTerms = UserDefaults.standard.string(forKey: "acceptedTerms")
if acceptedTerms != nil && acceptedTerms == "Yes" {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let VC = storyBoard.instantiateViewController(withIdentifier: "Home")
self.window?.rootViewController = VC
}
}
Second, modify UserDefaults.standard.string in somewhere
// example
#IBAction func acceptButtonTapped(_ sender: AnyObject) {
UserDefaults.standard.set("Yes", forKey: "acceptedTerms")
UserDefaults.standard.synchronize()
}

How to present different view controllers from appdelegate in ios

Actually I am having navigationcontroller as root controller it is embed in main.storyboard,i am having two screens one screen login and another one home as per login credentials i need to skip login screen and i need to show home screen.From appdelegate i am doing this skipping it is not working properly
Unbalanced calls to begin/end appearance transitions for <UINavigationController: 0x7fadf384c600>.
let storyboard=UIStoryboard.init(name: "Main", bundle: nil)
let navigationController=storyboard.instantiateInitialViewController()
let username=UserDefaultUtil.getString(key: AppConstants.PREF_USERID)
print(username!)
if username != ""
{
window?.rootViewController=navigationController
let sectionController=SectionController(nibName: "SectionController" , bundle: nil)
navigationController?.present(sectionController, animated: true, completion: nil)
}
I guess you are trying to present your sectionController in navigationController, its not really how it works, try this code:
let navigationController = self.storyboard?.instantiateInitialViewController() as! UINavigationController
and replace the present with this:
navigationController.setViewControllers([sectionController], animated: false)
or just drop the navigationController instantiate and create it with code and set it as window?.rootViewController:
let sectionController=SectionController(nibName: "SectionController" , bundle: nil)
let nav = UINavigationController(rootViewController: sectionController)
window?.rootViewController = nav
First, check the user credentials in the login page. Then use:
if hasCredentials {
let vc:AnyObject! = self.storyboard?.instantiateViewController(withIdentifier: "someViewController")
self.show(vc as! UIViewController, sender: vc)
}
Sidenote: Personally, I do this from the login page because it simplifies the process and I do not like having weight sitting in my AppDelegate. If you were thinking you did not want people seeing your login screen who are already members, you can do it from an AppDelegate, but take into account the user experience might be diminished during the loading process if this is the route you decide to take.

Resources