Why are these issues arising with my swift code? - ios

I am trying to implement a login through Parse, however, I am having a number of problems.
The first two If statements work but then perform a segue back to the first screen, even though there is no segue on my storyboard that even does this. So why is the alert popping up doing this? It doesn't wait or let me press OK.
When I sign up a user, it registers them (given the condition is met) to Parse but doesn't perform the segue which I have implemented? Fyi it doesn't show the alert error either.
On parse, there are frequently users signed up with random letters. I don't know how or why this happens.
Thank you in advance.
Jake
if passwordField.text == "" || confirmPasswordField.text == "" || usernameField == "" || lastNameField.text == "" || firstNameField.text == "" {
doAlert(title: "Incomplete Form", message: "You have not filled in all the forms")
} else if passwordField.text != confirmPasswordField.text {
doAlert(title: "Password mismatch", message: "Your passwords do not match")
} else {
let user = PFUser()
user.username = usernameField.text
user.password = passwordField.text
user["First Name"] = firstNameField.text
user["Last Name"] = lastNameField.text
user.signUpInBackground(block: { (success, error) in
if error != nil {
var displayMessage = "Please try again later"
if let errorMessage = error?.userInfo["error"] as? String {
displayMessage = errorMessage
} } else {
self.performSegue(withIdentifier: "RegisteredViewController", sender: self)
}
})
}

Related

How can I validate textField input with a Firestore query call?

So my goal is to validate a textfield by checking if that value is within any of the documents in the Firestore collection. So in my other validation function, I can return a String and show an alert with the error like so:
func validateFields() -> String? {
if nameTextF.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
emailTextF.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
passwordTextF.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
schoolIDTextF.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
currentGradeTextF.text?.trimmingCharacters(in: .whitespacesAndNewlines) == ""{
showAlert(title: "Missing Fields", message: "Please fill in all fields.")
return "Issue With Fields"
}
let cleanedPassword = passwordTextF.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let properGradeSelected = currentGradeTextF.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let validSchoolID = schoolIDTextF.text!.trimmingCharacters(in: .whitespacesAndNewlines)
if Utilities.isPasswordValid(cleanedPassword) == false {
showAlert(title: "Invalid Password", message: "Please ensure that your password contains 8 characters, contains a special character and a number as well.")
return "Issue With Password"
}
if Utilities.isGradeValid(properGradeSelected) == false {
showAlert(title: "Invalid Grade", message: "Please ensure that your current grade is valid.")
return "Issue With Grade Input"
}
if Utilities.isSchoolIDValid(validSchoolID) == false {
showAlert(title: "Invalid School ID Format", message: "The School ID entered has the incorrect format.")
return "Issue With School ID input."
}
return nil
}
Then I call it when the 'Sign Up' button is pressed like so:
#IBAction func signupPressed(_ sender: UIButton) {
//Validate the fields
let validationError = validateFields()
if validationError != nil {
return
} else {
//Create the user
Auth.auth().createUser(withEmail: email, password: password) { (result, err) in ....
This works perfect. Now since I want to use a Firestore query in a function, I can't return the String like how I did in the other ones without getting errors, so I'm quite confused on how to go about doing this.
This is the function I have so far:
func determineIfIDIsValid() {
let schoolIDText = schoolIDTextF.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
db.collection("school_users").whereField("school_id", isEqualTo: schoolIDText).getDocuments { (querySnapshot, error) in
guard error == nil else {
return
}
guard let query = querySnapshot?.isEmpty else { return }
if query == true {
//Show error alert
} else {
return
//Continue With Signup flow
}
}
}
I've tried declaring a variable before the query whether it be a String or Bool, changing the value after the query, and using logic to return a String but that didn't work either. How can I use this function to validate the specific field without getting any errors?
func determineIfIDIsValid(_ callback: #escaping (Bool) -> ()) {
let schoolIDText = schoolIDTextF.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
db.collection("school_users").whereField("school_id", isEqualTo: schoolIDText).getDocuments { (querySnapshot, error) in
guard error == nil else {
return
}
guard let query = querySnapshot?.isEmpty else { return }
if query == true {
//Show error alert
callback(true)
} else {
callback(false)
//Continue With Signup flow
}
}
}
Firebase calls are async. You need use closure
determineIfIDIsValid() { res in
if res {
//Show alert
} else {
//Continue With Signup flow
}

Check that username is unique is throwing Error: unexpected non-void return type in void function

I recently added
let username = usernameTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let db = Firestore.firestore()
db.collection("users").whereField("username", isEqualTo: username).getDocuments { (snapshot, error) in
if error == nil && snapshot?.documents != nil {
}
return "Username has already been taken"
}
to a validatefields() function, placed in a Register View Controller.
Since adding it, the line:
return "Username has already been taken"
is throwing an "Unexpected non-void return value in void function"
The entire function is:
func validateFields() -> String? {
//Check everything is filled in
if usernameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" || firstNameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" || lastNameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" || emailTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" || passwordTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" {
return "Please fill in all fields"
}
//Check if password is secure
let cleanedPassword = passwordTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
if Utilities.isPasswordValid(cleanedPassword) == false {
//Password isn't secure enough
return "Passwords must contain a minimum of 8 characters, using at least one capital, number and special character (!, ?, #, & etc.)"
}
let username = usernameTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let db = Firestore.firestore()
db.collection("users").whereField("username", isEqualTo: username).getDocuments { (snapshot, error) in
if error == nil && snapshot?.documents != nil {
}
return "Username has already been taken"
}
return nil
}
Any help would be massively appreciated.

Userdefault value comparison with textfield

i am trying to compare in login form password value with UserDefault value . but an error occur that bool operation cant be perform there.
Please can any one help me compare both values.
How can i compare these values?
if let savedPassword = UserDefaults.standard.string(forKey: "password") {
let enteredPassword = textField?.text
if savedPassword == enteredPassword {
// Do stuff.
}
}
else {
// Failure.
}
I wouldn't recommend storing passwords in plain text in UserDefaults.
There are a number of tutorials on this topic available, for example https://medium.com/ios-os-x-development/securing-user-data-with-keychain-for-ios-e720e0f9a8e2
Please use the below code snippet
if passwordField.text == UserDefaults.standard.string(forKey:"password"){
print("Same Password")
}
Thanks
You have to specify your object type
if UserDefaults.standard.string(forKey: "password") == passwordLabel.text {
// ...
}
I think you should cast your result from Any to String from User Defaults
if let yourString = UserDefaults.standard.string(forKey: "yourString"), yourString == passwordTextField.text {
// do something here
}

Firebase user display name causing crash

I'm running into a bug involving Firebase users displayName value. Here is my code:
if let user = user {
if user.displayName == nil || user.displayName == "" {
self.performSegue(withIdentifier: "AddName", sender: nil)
} else {
let displayName = user.displayName!.replacingOccurrences(of: " ", with: "_")
if let fcmToken = UserDefaults.standard.object(forKey: "firToken") as? String {
if !fcmToken.isEmpty {
ref.child("cities").child(driversCurrentCity).child("loggedInDrivers").child(displayName).child("fcmToken").setValue(fcmToken)
ref.child("cities").child(driversCurrentCity).child("loggedInDrivers").child("fcmTokens").child(fcmToken).setValue(true)
ref.child("users").child((FIRAuth.auth()?.currentUser?.uid)!).child("fcmToken").setValue(fcmToken)
UserDefaults.standard.set(true, forKey: "loginCompleted")
self.performSegue(withIdentifier: "LoggedInSuccess", sender: nil)
}
}
}
This is the code that I use to set the displayName:
I'm using this function from Firebase to set the displayName:
let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.displayName = displayName
changeRequest?.commitChanges { (error) in
// ...
}
For some users, everything works fine. However, some users experience a crash at the line
ref.child("cities").child(driversCurrentCity).child("loggedInDrivers").child(displayName).child("fcmToken").setValue(fcmToken)
I'm getting this error:
Fatal Exception: InvalidPathValidation
(child:) Must be a non-empty string and not contain '.' '#' '$' '[' or ']'
I haven't been able to replicate it lately, but when I
first started debugging the issue it was showing that displayName was some long string involving gestureRecognizer. It seems like some code when the sign in button is pressed is being applied to the displayName variable. I know this question is kind of vague but I appreciate any help!

Firebase - Unable to execute call to backend

I am working on a function that handles user registration and in the process, check if the selected username entered by the user is taken or not to inform the user to select a different one. I have the below code to accomplish this scenario:
#IBAction func proceedPressed(sender: AnyObject) {
/**********************Perform Validation************************/
if(self.emailTxtField.text != "" && self.passwordTxtField.text != "")
{
print("Email and Password not empty")
self.usernameValidation({(result) -> Void in
if(result == false)
{
print("Result False")
self.usernameErrorLabel.text = "Username Taken"
}else{
print("Result True")
//Username is available...Proceed
self.usernameErrorLabel.text = ""
FIRAuth.auth()?.createUserWithEmail(self.emailTxtField.text!, password: self.passwordTxtField.text!) { (user, error) in
if(error == nil)
{
print("Creating User with Email")
/*Create the user object as submitted*/
self.dbReference.child("users").child(user!.uid).setValue(["username": self.emailTxtField.text!,"name":self.nameTxtField.text!, "email":self.emailTxtField.text!, "mobile":self.mobileTxtField.text!, "homeAddress":"N", "workAddress":"N", "otherAddress":"N", "profilePictureRef":"N","telephone":"0","friendsCount":0, "retailersCount":0])
}else{
print("Error occured: \(error?.description)")
}
}//end of createUserWithEmail
}
})
}else{
print("Error: Email or Password field is empty")
}
}
and to check the username:
func usernameValidation(completion: (result: Bool) -> Void)
{
print("Username is: \(self.usernameTxtField.text!)")
dbReference.child("usernamesTaken").queryOrderedByValue().queryEqualToValue(self.usernameTxtField.text!).observeEventType(.Value, withBlock: { (snapshot: FIRDataSnapshot!) -> Void in
print(snapshot.childrenCount)
if(snapshot.childrenCount == 0)
{
print("result is true in username validation")
//Username Available
completion(result:true)
}else{
print("result is false in username validation")
//Username Taken
completion(result:false)
}
})
}
The problem with the above is that the full code doesn't seem to execute. When button pressed, I get the following messages in console:
- Email and Password not empty
- Username is: [value entered in usernameTxtField.text
and then nothing more. Although I wrote many print statements to try and see where this is stopping, but this is the furthest the code went in terms of printing the statements.
Is there something wrong here that I am missing out?
Thanks in advance.
I did some more testing and then discovered the issue through the xcode console. I copied the following from the firebase website to test fetching the data:
ref.child("users").child(userID!).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
// Get user value
let username = snapshot.value!["username"] as! String
let user = User.init(username: username)
// ...
}) { (error) in
print(error.localizedDescription)
}
The above showed an error that is "Permission Denied". Following that I edited the Rules in the database section in the console and allowed .read and .write and that did it. I thought I would post the details just in case someone else gets stuck.

Resources