Reputation: 4033
I have implemented a login to load data from a real-time database every time a user logs in. When the user has successfully logged in, the data is being read - the problem is that AppDelegate
changes the ViewController
faster than the data is being read. Therefore, nothing will be displayed until the app is closed again.
Is there a way to delay the change of the view until the data is read?
didFinishLaunchingOptions()
inside AppDelegate
:
let authListener = Auth.auth().addStateDidChangeListener { auth, user in
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if user != nil {
let controller = storyboard.instantiateViewController(withIdentifier: "RootPageViewController") as! RootPageViewController
self.window?.rootViewController = controller
self.window?.makeKeyAndVisible()
} else {
let vc = storyboard.instantiateViewController(withIdentifier: "SettingsTableViewController") as! SettingsTableViewController
vc.runResetData()
let controller = storyboard.instantiateViewController(withIdentifier: "ProfileViewController") as! ProfileViewController
self.window?.rootViewController = controller
self.window?.makeKeyAndVisible()
}
}
LoginViewController
:
@IBAction func login(_ sender: Any) {
guard let email = emailInput.text else { return }
guard let password = passwordInput.text else { return }
Auth.auth().signIn(withEmail: email, password: password) { user, error in
if error == nil && user != nil {
self.readData()
self.dismiss(animated: false, completion: nil)
} else {
print("Error logging in: ", error!.localizedDescription)
let alert = UIAlertController(title: "Fehler beim Einloggen", message: error!.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Verstanden", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
}
func readData() {
guard let uid = Auth.auth().currentUser?.uid else { return }
let databaseRef = Database.database().reference()
databaseRef.child("users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let monthlyStartKmData = value?["monthlyStartKm"] as? Int ?? 0
let currentKmData = value?["currentKm"] as? Int ?? 0
...
startKm = monthlyStartKmData
currentKm = currentKmData
...
}) { (error) in
print(error.localizedDescription)
}
}
Upvotes: 2
Views: 152
Reputation: 4033
There's a possibility to delay the change of view until Firebase was able to load its data:
databaseRef.observeSingleEvent
Working code:
let authListener = Auth.auth().addStateDidChangeListener { auth, user in
let databaseRef = Database.database().reference()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if user != nil {
databaseRef.observeSingleEvent(of: .value, with: { snap in
let controller = storyboard.instantiateViewController(withIdentifier: "RootPageViewController") as! RootPageViewController
self.window?.rootViewController = controller
self.window?.makeKeyAndVisible()
})
} else {
let vc = storyboard.instantiateViewController(withIdentifier: "SettingsTableViewController") as! SettingsTableViewController
vc.runResetData()
let controller = storyboard.instantiateViewController(withIdentifier: "ProfileViewController") as! ProfileViewController
self.window?.rootViewController = controller
self.window?.makeKeyAndVisible()
}
}
Upvotes: 0
Reputation: 100503
No you can't as the call to listen is asynchronous so it's run with a delay while the rootVC is setted , you need to show A loader like
let vc = UIViewController()
vc.view.backgroundColor = .red
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()
let authListener = Auth.auth().addStateDidChangeListener { auth, user in
.....
}
Inside AppDelegate
if FIRAuth.auth().currentUser != nil {
// go to home , if you went before you should have km month values cached
}
else {
// go to login
}
Upvotes: 2