Firebase uid returning nil after authentication (Swift) - ios

In my app, as soon as it opens I check to see if the user is already authenticated in the viewdidload of the initial view. If they are already authenticated, I perform a segue to the main view. I'm even printing the uid to the log at this time and it's printing correctly.
override func viewDidLoad() {
super.viewDidLoad()
if ref.authData != nil {
let uid = ref.authData.uid
print(uid)
I then do the same later in the app to get some of the user's info when they click on their profile settings. I write the exact same code to fetch their uid, but this time the uid is returning nil and is crashing with the error
"fatal error: unexpectedly found nil while unwrapping an Optional value"
Is this a firebase or simulator issue?
Edit: This issue has only occurred twice. Otherwise, the code itself works as intended, which makes me wonder whether it is a firebase or simulator issue.

You want to use the observeAuthEventWithBlock method, which is a realtime authentication listener.
override func viewDidAppear() {
let ref = Firebase(url: "https://<YOUR-FIREBASE-APP>.firebaseio.com")
ref.observeAuthEventWithBlock({ authData in
if authData != nil {
// user authenticated
print(authData)
self.performSegueWithIdentifier("LoginToOtherView", sender: nil)
} else {
// No user is signed in
}
})
}

About the exact error you are encountering I am not sure, but a Swift-yer way of doing your code (and avoiding your error) would be to call:
if let uid = ref.authData.uid {
print(uid)
}
This code safely unwraps both authData and the UID.

I was having this problem and it took me hours. Then I realized that I'd just forgotten to do this:
ref = FIRDatabase.database().reference()
before
var ref: FIRDatabaseReference!

Related

Firebase database observer does not retrieve data

I have an iOS App that uses Firebase to store user information. I cannot seem to get the observe() block ran in anyway. The closure is never executed.
When I debug the code, I see that the observe() block is skipped hence I cannot validate the user information.
From the Firebase console, I can verify a table with a name equal to hashCode exists and the table in fact has a checked field.
I use Xcode 9.3 and Swift 4.1
What am I missing here?
Thanks
override func viewDidLoad() {
super.viewDidLoad()
// UI changes
self.view.backgroundColor = appBgColour
// check if the user has registered before
if let asciiCode = defaults.string(forKey: "asciiCode") {
let hashCode = userCode.myHash() // myHash() is an extension to String
dbReference = Database.database().reference(withPath: databaseReferenceName)
dbReference.child("\(hashCode)/checked").observe(.value) { (snapshot) in
if snapshot.exists() {
// a table with this user's Hash'ed code exists
self.isRegistrationNeeded = false
} else {
// user needs to register with a new list
self.isRegistrationNeeded = true
}
}
}
}

Parse User Auto Login

I'm trying to get my app to segue directly to the Profile Page after start is a PFUser is already logged in that way they won't have to keep logging in unless the completely stop the app. It's not working. Maybe I'm not checking for PFUser nil correctly. Please help. Here's what I'm putting in viewDidLoad.....
override func viewDidLoad()
{
super.viewDidLoad()
if PFUser.currentUser()?.username != nil
{
self.performSegueWithIdentifier("loginToProfileSegue", sender: self)
}
Please help.

Update cached copy of Parse currentUser() in Swift

I have an ios application, I have implemented Facebook login through Parse. Everything works great in the first trial.
I can login via Facebook
My details are stored in the PFUser.currentUser()
I am able to pull information from the Graph API
But things start to become a problem when I logout (PFUser.logOut()) , and delete the User row from the Parse class and delete the app from Facebook.
The following methods still show that the user is logged in and authenticated.
if let user = PFUser.currentUser() {
if user.isAuthenticated()
I am guessing it is because current user is still using the cached copy of the User. I try executing
do
{
try PFUser.currentUser().fetch()
}
catch{
print("User refreshed")
}
But it does not refresh the currentUser() and gives an error. How can I refresh the PFUser.currentUser(), so that it stops saying that the user is logged in and authenticated, even though it's not
Thanks
I got an answer here,
Swift & Parse - PFUser currentUser never equals nil
I've been struggling with logging out for a little while and I believe I have finally cracked it!
No matter what I did, when I used "PFUser.logOut()" would never set "PFUser.currentUser()" to nil, but it would set "PFUser.currentUser()!.username" to nil...
Because of this I used
var currentUser = PFUser.currentUser()!.username
as a global variable to track is a user is logged in.
On my login/first page I added
override func viewDidAppear(animated: Bool) {
if currentUser != nil {
self.performSegueWithIdentifier("login", sender: self)
}
}
and finally on my logout button i used
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "logout" {
PFUser.logOut() //Log user out
currentUser = PFUser.currentUser()!.username //Reset currentUser variable to nil
}
}

Current User isn't nil after calling PFUser.logOut() parse, swift2

I want to build a simple LogOut Button with parse but the current user is not getting nil.
PFUser.logOut()
var currentUser = PFUser.currentUser() // this should be nil but it isn't :(
print(currentUser)
I also tried:
PFUser.logOutInBackground()
var currentUser = PFUser.currentUser() // this is also not nil :(
So when I print the currentUser it is not nil like it should be. It is:
Optional(<PFUser: 0x7f8d99dd2320 , objectId: new, localId: local_58d62becf7a6f1dc> {
})
So I think the app is creating a new user?!
Try commenting out the following line of code in your AppDelegate.swift file -
PFUser.enableAutomaticUser()
enableAutomaticUser() will log in an anonymous user once you call PFUser.logOut(), and the username for an anonymous user is nil.
Check to see if we have a currentUser in the AppDelegate in the didFinishLaunchingWithOptions method
let user = PFUser.currentUser()
if user == nil
{
// present loginViewController
}
else
{
print("user is \(user?.username)") // <--- who is currently
// show any viewcontroller
}
Your logout Button should send the user back to the loginViewController after Login out of your app.
Example:
#IBAction func Logout(sender:UIButton)
{
PFUser.Logout()
let LoginViewController = storyboard.instantiateViewControllerWithIdentifier("storyBoardID")
self.presentViewController(LoginViewController, animated: true, completion: nil)
}
So From the Login View Controller, they could use their credentials to sign in back into your app, then the currentUser won't return a nil
Set return type of the function(logout) as optional type. Only optionals has the capability of holding nil value.
Here is the example that i want to tell you
func loggedOut() -> Int? {
// check you conditions here ex:
if score > 0 {
return score
} else {
return nil
}
}

Parse PFUser.currentUser returns nil - Swift

I am logging in my users using Parse. As my app opens my LaunchVieWController determines whether users are already signed in or not:
override func viewDidLoad() {
super.viewDidLoad()
//Make sure cached users don't have to log in every time they open the app
var currentUser = PFUser.currentUser()
println(currentUser)
if currentUser != nil {
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("alreadySignedIn", sender: self)
}
} else {
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("showSignUpIn", sender: self)
}
}
}
If users are already signed in they are taken to the table view described below. If they are not logged in, they are taken to a view in which they can go to the signup view or the login view.
My signup works perfectly fine, and signs up users and then redirects them to the table view.
Here is the signup function (it is in a separate controller from the login function):
func processSignUp() {
var userEmailAddress = emailAddress.text
var userPassword = password.text
// Ensure username is lowercase
userEmailAddress = userEmailAddress.lowercaseString
// Add email address validation
// Start activity indicator
activityIndicator.hidden = false
activityIndicator.startAnimating()
// Create the user
var user = PFUser()
user.username = userEmailAddress
user.password = userPassword
user.email = userEmailAddress
user.signUpInBackgroundWithBlock {
(succeeded: Bool, error: NSError?) -> Void in
if error == nil {
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("signInToNavigation", sender: self)
}
} else {
self.activityIndicator.stopAnimating()
if let message: AnyObject = error!.userInfo!["error"] {
self.message.text = "\(message)"
}
}
}
}
My login function looks like so:
#IBAction func signIn(sender: AnyObject) {
var userEmailAddress = emailAddress.text
userEmailAddress = userEmailAddress.lowercaseString
var userPassword = password.text
PFUser.logInWithUsernameInBackground(userEmailAddress, password:userPassword) {
(user: PFUser?, error: NSError?) -> Void in
if user != nil {
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("signInToNavigation", sender: self)
}
} else {
if let message: AnyObject = error!.userInfo!["error"] {
self.message.text = "\(message)"
}
}
}
}
After users log in they are sent to a table view. In that table view I am trying to access the current user object in the following function, as I want to load different data based on who the user is:
override func queryForTable() -> PFQuery {
var query = PFQuery(className:"MyClass")
query.whereKey("userID", equalTo: PFUser.currentUser()!)
return query
}
When I try to log in with a user I get thrown the following error: "fatal error: unexpectedly found nil while unwrapping an Optional value". It seems like the PFUser.currentUser() object is nil.
When users are sent to the table view after signing up the PFUser.currentUser() object is set and works perfectly.
My guess is that this is because of the fact that the PFUser.logInWithUsernameInBackground is happening in the background and that my query is trying to get the PFUser.currentUser() object before it has been loaded. Is there anyway I can work around this issue? In the table view the value of PFUser.currentUser() is needed to load the table data. Can I somehow make sure that PFUser.currentUser() gets assigned with the current user object before the function gets called (for example, by not loading in users in the background thread)?
All help is much appreciated!
EDIT: I've updated this post with some more of my code to help highlight any bug that I may be missing.
I discovered that this problem appeared because the segue signInToNavigation was wired from the Login-button, instead from the login view controller itself. This resulted in the segue being executed before the login function was executed, and therefore the PFUser.currentUser()object was not yet assigned when the table view loaded. I solved this by rewiring the segues. Stupid slip-up on my side.
Thanks to Ryan Kreager and Wain for taking time to help me figure out this issue!
You can try checking if PFUser.currentUser() != nil instead to make sure it's being set right after login. If it's not being set right off the bat, you know there is a deeper login problem.
Also, try removing the dispatch_async(dispatch_get_main_queue()){ wrapper around your call to the segue.
It's unnecessary (logInWithUsernameInBackground already returns to the main thread) and I have a hunch that it's creating a racing condition where the local object is not being set first because Parse can't do any post-call cleanup since you're going right for the main thread.

Resources