I am trying to recovery a value from firebase database and compare it with a UITextField value, in case of matching, I save it to a var that I will us. The problem is that the variable in question has a default value just when I use it.
Above I show my func code where the variable affected is "codeRecovered":
#IBAction func signUpAction(_ sender: AnyObject)
{
var codeRecovered: String = ""
if emailSignUpTextField.text == "" || self.secretCodeTextField.text == "" {
let alertController = UIAlertController(title: "Error", message: "Please enter your email, pin code and password", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
} else {
self.dbHandler = self.ref?.child("Companies").observe(.value, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let value = snap.value as! [String:String]
if let auxSecretCode = value["secretCode"]
{
if auxSecretCode == self.secretCodeTextField.text{
print("Value recovered OK(works fine): \(auxSecretCode)")
codeRecovered = auxSecretCode
print("Recovered value saved OK(works fine): \(codeRecovered)")
}
}
}
})
//Here codeRecovered is already ""
print("\(codeRecovered) is the recovered value(empty) and \(self.secretCodeTextField.text ?? "def") is the textField value")
if codeRecovered != self.secretCodeTextField.text{
let alertController = UIAlertController(title: "Error", message: "Please enter a correct pin code", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
}
//....
Async calls with sync result use....
#IBAction func signUpAction(_ sender: AnyObject)
{
var codeRecovered: String = ""
if emailSignUpTextField.text == "" || self.secretCodeTextField.text == "" {
let alertController = UIAlertController(title: "Error", message: "Please enter your email, pin code and password", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
} else {
self.dbHandler = self.ref?.child("Companies").observe(.value, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let value = snap.value as! [String:String]
if let auxSecretCode = value["secretCode"]
{
if auxSecretCode == self.secretCodeTextField.text{
print("Value recovered OK(works fine): \(auxSecretCode)")
codeRecovered = auxSecretCode
print("Recovered value saved OK(works fine): \(codeRecovered)")
}
}
}
//Here codeRecovered is already ""
print("\(codeRecovered) is the recovered value(empty) and \(self.secretCodeTextField.text ?? "def") is the textField value")
if codeRecovered != self.secretCodeTextField.text{
let alertController = UIAlertController(title: "Error", message: "Please enter a correct pin code", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
}
})
to use your codeRecovered in a sequence it must be within self.dbHandler = self.ref?.child("Companies").... block because it runs in async thread
Related
My app crashes and quit when user try to register a new account but that occurs on any device except devices deployed the app with Xcode.
All the devices are registered in the developer account and running iOS 11.4.1
Here is the register button function:
#IBAction func regButton(_ sender: Any) {
usernameText = usernameTextField.text
mobileText = mobileTextField.text
emailText = emailTextField.text
passwordText = passwordTextField.text
fieldText = categoryTextField.text
print(usernameText ?? "damn")
print(mobileText ?? "damn")
print(emailText ?? "damn")
print(passwordText ?? "damn")
print(fieldText ?? "damn")
if(type=="Seeker")
{
let url1 = "http://app.alosboiya.com.sa/hourjob.asmx/insert_jobseeker?name="+usernameText!+"&phone="+mobileText!
let url2 = "&email="+emailText!+"&password="+passwordText!+"&workex="+"companyDescText!"
let url3 = "&category="+fieldText!+"&image="+"downloadURLGlobal!"
let url4 = "&unpaidhour="+"string"+"&hourpaidlast30="+"string"+"&totalhourworked="+"string"+"&balance="+"string"+"&username="+usernameText!
stringURL = url1 + url2 + url3 + url4
}else
{
let url1 = "http://app.alosboiya.com.sa/hourjob.asmx/insert_company?name="+usernameText!+"&field="+fieldText!
let url2 = "&phone="+mobileText!+"&email="+emailText!+"&password="+passwordText!+"&workex="+"companyDescText!"+"&crcopy="+"downloadURLGlobal!"+"&logo="+"string"+"&username="+usernameText!
stringURL = url1 + url2
}
if Reachability.isConnectedToNetwork()
{
if(checkbox.on==true)
{
let url = URL(string: stringURL!)
Alamofire.request(url!).responseString {
(response) in
let result = response.result.value
do {
if(result=="True")
{
let alert = UIAlertController(title: "Registration Successfully", message: "Registration Done Successfully Congratulations",
preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style:
UIAlertActionStyle.default, handler: self.doSomething))
self.present(alert, animated: true, completion: nil)
}else
{
let alert = UIAlertController(title: "Registration Failed", message: "Registration Failed Please Try Again", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
}
}
}else
{
let alert = UIAlertController(title: "License Agreement", message: "Check to Agree Licence Agreement", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
}else
{
let alert = UIAlertController(title: "No Network Connection", message: "Connection Error Please Try Again", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
}
If a user will tap the button but one or both text fields are empty then your app will crash due to forced unwraping (! mark) which you use in your code.
Example: if mobileText field will be empty then the your app will crash:
let url1 = "http://app.alosboiya.com.sa/hourjob.asmx/insert_jobseeker?name="+usernameText!+"&phone="+mobileText!
the solution is to use guard statement
guard let usernameText = usernameTextField.text,
mobileText = mobileTextField.text,
emailText = emailTextField.text,
passwordText = passwordTextField.text,
fieldText = categoryTextField.text else {
return
}
more specifically the error warning I ma getting is:
Attempt to present UIAlertController whose view is not in the window hierarchy!
I am currently creating a signup page that ask user to fill few specific details such as Name, Country, Email, Password and etc. To make sure user provide all the relevant information I am trying to write a code to send an alert if user does not provide all the information. I have wrote the code taking help from stakeoverflow.
Problem: Whenever user left any field blank it is not showing the alert and by default performing a segue that takes user to signin page. This is the first time I am creating an alert and hence don't what is going wrong (I believe 95% of my code is in place)
can anyone help?
#IBAction func signUpPressed(_ sender: Any) {
if nameText.text!.isEmpty || genderText.text!.isEmpty || countryText.text!.isEmpty || yourSchool.text!.isEmpty || yourClass.text!.isEmpty {
print("Please fill all fields")
//my code is printing above error in the Xcode console but the below code is not working
//setting error message if not all fiels filled
let alertController = UIAlertController(title: "Error", message: "Please fill all fields", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
}
else {
Auth.auth().createUser(withEmail: yourEmail.text!, password: yourPassword.text!) { (user, error) in
if error != nil {
///print errror message
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
} else {
print("You have successfully signed up")
self.performSegue(withIdentifier: "JoinUs2SignPage", sender: self)
//updating user information
let userID = Auth.auth().currentUser!.uid
let usertype: String = "Student"
self.ref.child("users").child(userID).setValue(["usertype": usertype ,"username": self.nameText.text!, "usergender": self.genderText.text!, "usercountry": self.countryText.text!, "userschool": self.yourSchool.text!, "userclass": self.yourClass.text!,])
}
}
}
Action may be out of main thread
DispatchQueue.main.async {
///print errror message
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
Try this approach
check for white space like that
let nameTrimmed = self.nameText.text?.trimmingCharacters(in: .whitespacesAndNewlines)
let genderTrimmed = self.genderText.text?.trimmingCharacters(in: .whitespacesAndNewlines)
let countryTrimmed = self.countryText.text?.trimmingCharacters(in: .whitespacesAndNewlines)
let schoolTrimmed = self.schoolText.text?.trimmingCharacters(in: .whitespacesAndNewlines)
if nameTrimmed.text == "" || genderTrimmed.text == "" || countryTrimmed.text == "" || schoolTrimmed.text == ""
#IBAction func registerPressed(_ sender: Any) {
if nameText.text!.isEmpty || genderText.text!.isEmpty || countryText.text!.isEmpty || yourSchool.text!.isEmpty || yourClass.text!.isEmpty {
print("Please fill all fields") //my code is printing this error
//alert message popup
let alertController = UIAlertController(title: "Error", message: "Please fill all fields", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action:UIAlertAction) in
print("Okay")
}))
let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alertController, animated: true, completion: nil)
}
else {
Auth.auth().createUser(withEmail: yourEmail.text!, password: yourPassword.text!) { (user, error) in
if error != nil {
///print errror message
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action:UIAlertAction) in
print("Okay")
}))
let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert + 1;
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alertController, animated: true, completion: nil)
}
else {
print("You have successfully signed up")
self.performSegue(withIdentifier: "JoinUs2SignPage", sender: self)
//updating user information
let userID = Auth.auth().currentUser!.uid
let usertype: String = "Student"
self.ref.child("users").child(userID).setValue(["usertype": usertype ,"username": self.nameText.text!, "usergender": self.genderText.text!, "usercountry": self.countryText.text!, "userschool": self.yourSchool.text!, "userclass": self.yourClass.text!,])
}
}
}
}
When I save data under userID the data is not being stored into the Firebase and give error unexpectedly found nil while unwrapping an optional value, however when I use childByAutoID the data is being stored successfully. Help me to save under userID node. Here I have explained that when I create the user under signup action this is happening.
#IBAction func createAccountAction(_ sender: Any) {
if self.emailTextField.text == "" || self.passwordTextField.text == "" {
let alertController = UIAlertController(title: "Error", message: "Please enter your email and password", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
} else if (self.passwordTextField.text != self.retypePasswordfield.text) {
let alertController = UIAlertController(title: "Error", message: "Password does not match", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
} else {
ref.child("user_registration").setValue(["username": self.fullName.text, "email": self.emailTextField.text,"contact": self.numberText.text, "city": self.myCity.text, "state": self.countryText.text, "gender": genderGroup, "blood": bloodGroup])
FIRAuth.auth()?.createUser(withEmail: emailTextField.text!, password: passwordTextField.text!) { (user, error) in
if error == nil {
FIRAuth.auth()?.currentUser!.sendEmailVerification(completion: { (error) in
})
print("You have successfully signed up")
let alertController = UIAlertController(title: "Successful!", message: "Email Verification link sent", preferredStyle: .alert)
let alertActionOkay = UIAlertAction(title: "Okay", style: .default) { (action) in
let vc = self.storyboard?.instantiateViewController(withIdentifier: "LoginFirstViewController")
self.present(vc!, animated: true, completion: nil)
}
alertController.addAction(alertActionOkay)
self.present(alertController, animated: true, completion: nil)
} else {
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}
}
}
Only for reference
This is the current working code for me
On signUp Button
// Create new User
FIRAuth.auth()?.createUser(withEmail: self.tfEmail.text!, password: self.tfPassword.text!, completion: { (user, error) in
if error == nil{ // IF NO ERROR
let astrContact = self.strDialCode + " " + self.tfMobileNumber.text!
// Dict to add user data in firebase Db
let aDBDict : [String : String] = ["userName": self.tfFullName.text!,
"userEmail": self.tfEmail.text!,
"userContact": astrContact,
"userCountry": self.strCode,
"userID": (user?.uid)!]
// Add data in DB
ref?.child("Customer/\(String(describing: (user?.uid)!)/userProfileDetails").setValue(aDBDict)
DispatchQueue.main.async(execute: { () -> Void in
// goto home VC
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navController = storyboard.instantiateViewController(withIdentifier: "MainController")
if let window = AppDelegate.getAppDelegate().window {
window.rootViewController = navController
}
})
}
else{ // If error in creating new user
print("error in creating new user")
print(error!)
}
})
In appDelegate
extension AppDelegate {
class func getAppDelegate() -> AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
}
This is my swift code
i will get above error on this line : guard (newUser["status"] as! Int != 0)
#IBAction func signInButton(_ sender: UIButton) {
if validator(){
DispatchQueue.global(priority: DispatchQueue.GlobalQueuePriority.default).async(execute: {
let datas:[String:String] = ["email":self.emailField.text!,"name": self.nameField.text!,"password" : self.passwordField.text!]
DispatchQueue.main.async {
SwiftSpinner.show("Signin' in...")
}
let newUser:NSDictionary = self.marketcloud!.createUser(datas)
print(newUser)
DispatchQueue.main.async {
SwiftSpinner.hide()
guard (newUser["status"] as! Int != 0) else {
let alertController = UIAlertController(title: "Error", message: "Email already in use. Try with a different one!", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Close",
style: UIAlertActionStyle.destructive,
handler: nil))
self.present(alertController, animated: true, completion: nil)
return
}
let alertController = UIAlertController(title: "Ok!", message: "User created successfully!", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.default, handler: {(action:UIAlertAction) in
UserData.setLastRegisteredUser(self.emailField.text!, password: self.passwordField.text!);
print("Setted UserData \n \(UserData.getLastRegistedUserEmail(),UserData.getLastRegisteredUserPassword())")
//returns to the login view
let next = self.storyboard!.instantiateViewController(withIdentifier: "viewController") as! ViewController
next.downloadProducts = false
next.load = true
self.navigationController?.pushViewController(next, animated: true)
}));
self.present(alertController, animated: true, completion: nil)
}
})
}
}
Try to understand how guard works.
The condition must be an optional binding with let or a boolean expression
guard let status = newUser["status"] as? Int, status != 0 else { ...
And no parentheses in Swift.
I have some code in my project:
#IBAction func createAccountAction(sender: AnyObject) {
if self.emailField.text == "" || self.passwordField.text == ""
{
let alertController = UIAlertController(title: "Oops!", message: "Please enter an email and password.", preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
else
{
FIRAuth.auth()?.createUserWithEmail(self.emailField.text!, password: self.passwordField.text!) { (user, error) in
if error == nil
{
let alertController = UIAlertController(title: "Done", message: "Account created!", preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alertController.addAction(defaultAction)
self.emailField.text = ""
self.passwordField.text = ""
}
else
{
let alertController = UIAlertController(title: "Oops!", message: error?.localizedDescription, preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
As you can see in the last else statement I have a alertController with the message Oops that will show when clicking the createAccountAction button.
But that happens when the user presses the button and has not filled in anything in the textfields.
Now what I want is that when a user succesfully fills in the textfields, that a same popup should appear along with other text that I specified.
When I run the code it does the part
self.emailField.text = ""
self.passwordField.text = ""
but does not present the AlertController.
How can I achieve what I want?
You're missing the line:
self.presentViewController(alertController, animated: true, completion: nil)
which should be after:
self.emailField.text = ""
self.passwordField.text = ""
So you aren't presenting the alert.
Also. You can change that entire function to this much simpler one:
#IBAction func createAccountAction(sender: AnyObject) {
if self.emailField.text == "" || self.passwordField.text == "" {
let title = "Oops"
let message = "Please enter an email and password."
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
} else {
FIRAuth.auth()?.createUserWithEmail(self.emailField.text!, password: self.passwordField.text!) { (user, error) in
var title : String
var message : String
if error == nil {
title = "Done"
message = "Account created!"
self.emailField.text = ""
self.passwordField.text = ""
} else {
title = "Oops!"
message = "error?.localizedDescription"
}
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
}
}
You are only presenting the alert controller in the 'else' part of your 'if else' statement.
Additionally refactored example to ensure bugs like that don't happen:
var title: String!
var message: String!
if let error = error {
title = "Oops!"
message = error.localizedDescription
} else {
title = "Done"
message = "Account created!"
self.emailField.text = ""
self.passwordField.text = ""
}
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)