Optional Text in Alert in ResetPassword - iOS Project using Swift - ios

Here's my ResetPassword Button for my iOS application using xcode and swift:
//ResetPssword Button
#IBAction func ResetPassword(sender: AnyObject) {
if validateEmail(EmailTextField.text!) == false {
print("Enter a Valid Email Address")
let VaildMessage = "Enter an Email Address"
//Empty TextField Alert Message
self.disaplayErrorMessage(VaildMessage)
}
//Reset
else {
ref.resetPasswordForUser(EmailTextField.text) { (ErrorType) -> Void in
if ErrorType != nil {
let error = ErrorType
print("There was an error processing the request \(error.description)")
let errorMessage:String = "The Email You Entered is not Exist"
//Error Alert Message
self.disaplayErrorMessage(errorMessage)
} else {
print("Password Reset Sent Successfully")
let successMessage = "Email Message was Sent to You at \(self.EmailTextField.text)"
//Success Alert Message
self.disaplayErrorMessage(successMessage)
}
} //reset
} //Big Else
} //Button
//Display Alert Message With Confirmation
func disaplayErrorMessage(theMessage:String)
{
//Display alert message with confirmation.
let myAlert = UIAlertController(title: "Alert", message: theMessage, preferredStyle: UIAlertControllerStyle.Alert);
let OkAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default) {
action in
self.dismissViewControllerAnimated(true, completion: nil);
}
myAlert.addAction(OkAction);
self.presentViewController(myAlert, animated: true, completion: nil)
}
//Validate Email Function
func validateEmail(candidate: String) -> Bool {
let emailRegex = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}"
return NSPredicate(format: "SELF MATCHES %#", emailRegex).evaluateWithObject(candidate)
}
If the password reset sent successfully, there will be an alert that prints out the email address. But it prints email with optional word!
How can I print it without the optional word?

You have to unwrap the Optional text field.
For example with if let:
if let text = self.EmailTextField.text {
let successMessage = "Email Message was Sent to You at \(text)"
//Success Alert Message
self.disaplayErrorMessage(successMessage)
}

Did you tried to force unwrap the value using the ! sign ?

Related

Alert controller not being presented even though condition is met (value is empty)

I've been having an issue with a personal app where certain users seem to be missing a profile picture when they sign up (String). I've added a check to make sure the string isn't empty when the user presses the "Next" button - basically check if the string is "", and if so, present an alert controller to remind them to choose a profile picture. If it's not empty, then segue to the next screen. This is the relevant code (for clarity, var emailUserPicString = "" is a global variable):
emailUserPicString = url.absoluteString
print("\n\n\npic:\(emailUserPicString)\n\n\n")
if emailUserPicString == "" {
let alertController = UIAlertController(title: "Profile Picture Error", message: "Don't forget to choose a profile picture!", preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {(alert :UIAlertAction!) in
})
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: nil)
return
} else {
self.performSegue(withIdentifier: "emailToSetup", sender: nil)
}
Now, when I test this solution, pressing the Next button doesn't do anything, and no alert is presented. I'd think it would be one or the other - if the string is empty, the alert controller would be shown, and if there's a value, performSegue would happen and we'd be taken to the next screen. I'm wondering why neither of these are happening
This is the complete function if it can provide some context:
#IBAction func emailSignupNextPressed(_ sender: Any) {
// Make sure text fields aren't empty
guard nameField.text != "", emailField.text != "", passwordField.text != "", confirmPasswordField.text != "" else {return}
if passwordField.text == confirmPasswordField.text {
Auth.auth().createUser(withEmail: emailField.text!, password: passwordField.text!, completion: { (user, error) in
if let error = error {
print(error.localizedDescription)
}
if let user = user {
guard let uid = Auth.auth().currentUser?.uid else {return}
// Use name as Firebase display name for readability
let changeRequest = Auth.auth().currentUser!.createProfileChangeRequest()
changeRequest.displayName = self.nameField.text!
changeRequest.commitChanges(completion: nil)
// Create child node from userStorage "users". Profile image set to user's unique ID
let imageRef = self.userStorage.child("\(uid).jpg")
let data = UIImageJPEGRepresentation(self.selectProfileImageView.image!, 0.5)
// Upload image to Firebase
let uploadTask = imageRef.putData(data!, metadata: nil, completion: { (metadata, err) in
if err != nil {
print(err!.localizedDescription)
}
imageRef.downloadURL(completion: { (url, er) in
if er != nil {
print(er?.localizedDescription as Any)
}
if let url = url {
emailUserPicString = url.absoluteString
print("\n\n\npic:\(emailUserPicString)\n\n\n")
if emailUserPicString == "" {
let alertController = UIAlertController(title: "Profile Picture Error", message: "Don't forget to choose a profile picture!", preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {(alert :UIAlertAction!) in
})
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: nil)
return
} else {
self.performSegue(withIdentifier: "emailToSetup", sender: nil)
}
}
})
})
uploadTask.resume()
}
})
} else {
// print("Passwords don't match")
passwordAlert()
}
}
My question is, am I handling the string check correctly? If there's no value there, why is my alert controller not presenting? And if there is a value why is the segue not being performed?
As I can see, you are presenting the UIAlertAction in a background Thread. So, you should present it in the UI Thread using:
DispatchQueue.main.async {
// show alert here
}
try to change your if statement to
if emailUserPicString.isEmpty || emailUserPicString.isEmpty == ""{
}
Maybe an empty textField don't has a == "" String
Follow this solution:
private func validateForm() {
if emailTextField.text?.isEmpty {
// Show alert message like: Please enter the email addess.
return
}
if passwordTextField.text?.isEmpty && passwordTextField.text?.count < 6 {
// Show alert message like: Password must be at least 6 chars long.
return
}
if profleImage.image == nil {
// Show alert message like: Please choose your profile photo.
return
}
// Now you can post API request after validating all values.
// Call here API request method.....
}

Swift iOS How to display an alert message from the handler of another alert message

I'm trying to implement a forgot password feature in my app so users can enter their email in and have it reset in the database and have the new generated password emailed to them.
I believe my code should work once I fix a few minor issues but the main hurdle I'm having is how to display an alert message from the handler of another alert message.
Any idea how to do it? Either the alert message doesn't show up at all or the first one doesn't close at all.
Here is my attempt at it:
//This function will send a password reset email
func emailPassword(alertAction: UIAlertAction!) -> Void {
let textField = reset_alert.textFields![0] as UITextField
if(!textField.text!.isEmpty){
if(textField != "mik"){
let query = PFQuery(className: "_User")
let forgotten_email = textField.text
query.whereKey("email", equalTo: forgotten_email!)
query.findObjectsInBackgroundWithBlock{
(objects: [PFObject]?, error: NSError?) -> Void in
//NO ERROR//
if(error == nil){
//email in db generate random password
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let randomString : NSMutableString = NSMutableString(capacity: 12)
var users_name = ""
for _ in 0...10{
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
//set new password for user
if let objects = objects {
for object in objects {
object["_hashed_password"] = randomString
users_name = object["name"] as! String
//send password to email
self.mailgun.sendMessageTo("\(users_name) <\(textField)>", from: "")
self.displayAlert("SUCCESS", msg: "Check your email for your new password")
self.reset_alert.dismissViewControllerAnimated(true, completion: nil)
}
}
else{
self.reset_alert.dismissViewControllerAnimated(true, completion: nil)
self.displayAlert("ERROR", msg: "Email not registered to an account")
}
}
//ERROR//
else{
self.reset_alert.dismissViewControllerAnimated(true, completion: nil)
self.displayAlert("ERROR", msg: "Email not registered to an account") }
} //end if textfield not admin email
self.presentViewController(reset_alert, animated: true, completion: nil)
}
}//end of if textfield is empty
}
Try this extension:
typealias AlertActionBlock = (UIAlertAction) -> Void
extension UIViewController {
func flash(title title:String?, message:String?, cancelTitle:String?, actions:UIAlertAction?...) {
let b = {
let alertController = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
let cancelBlock:AlertActionBlock = {(action:UIAlertAction) -> Void in }
let cancelAction = UIAlertAction(title: cancelTitle, style: UIAlertActionStyle.Cancel, handler: cancelBlock)
alertController.addAction(cancelAction)
for action in actions {if let action = action {alertController.addAction(action)}}
self.presentViewController(alertController, animated: true, completion: nil)
}
if NSThread.isMainThread() {
b()
} else {
dispatch_async(dispatch_get_main_queue(), b)
}
}
}
That should let you call that function from background threads or the main thread just call that function and fill in the variables
EDIT (I didn't realize you need a textfield) so try this:
func flash(title title:String?, message:String?, textFieldConfigurator:(UITextField -> Void)? = nil, cancelTitle:String?, actions:UIAlertAction?...) {
let b = { () -> Void in
let alertController = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
if let textFieldConfigurator = textFieldConfigurator {alertController.addTextFieldWithConfigurationHandler(textFieldConfigurator)}
let cancelBlock:AlertActionBlock = {(action:UIAlertAction) -> Void in }
let cancelAction = UIAlertAction(title: cancelTitle, style: UIAlertActionStyle.Cancel, handler: cancelBlock)
alertController.addAction(cancelAction)
for action in actions {if let action = action {alertController.addAction(action)}}
self.presentViewController(alertController, animated: true, completion: nil)
}
if NSThread.isMainThread() {
b()
} else {
dispatch_async(dispatch_get_main_queue(), b)
}
}
If you need multiple text fields make it an array and iterate through it. Let me know how it goes!

Handling Email Does not Exist Error - iOS project using swift

Here's my ResetPassword Button for my iOS application using xcode and swift:
//ResetPssword Button
#IBAction func ResetPassword(sender: AnyObject) {
if validateEmail(EmailTextField.text!) == false {
print("Enter a Valid Email Address")
let VaildMessage = "Enter an Email Address"
//Empty TextField Alert Message
self.disaplayErrorMessage(VaildMessage)
}
//Reset
else {
ref.resetPasswordForUser(EmailTextField.text) { (ErrorType) -> Void in
if ErrorType != nil {
let error = ErrorType
print("There was an error processing the request \(error.description)")
let errorMessage:String = "The Email You Entered is not Exist"
//Error Alert Message
self.disaplayErrorMessage(errorMessage)
} else {
print("Password Reset Sent Successfully")
if let Email = self.EmailTextField.text {
let successMessage = "Email Message was Sent to You at \(Email)"
//Success Alert Message
self.disaplayErrorMessage(successMessage) }
}
} //reset
} //Big Else
} //Button
//Display Alert Message With Confirmation
func disaplayErrorMessage(theMessage:String)
{
//Display alert message with confirmation.
let myAlert = UIAlertController(title: "Alert", message: theMessage, preferredStyle: UIAlertControllerStyle.Alert);
let OkAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default) {
action in
self.dismissViewControllerAnimated(true, completion: nil);
}
myAlert.addAction(OkAction);
self.presentViewController(myAlert, animated: true, completion: nil)
}
//Validate Email Function
func validateEmail(candidate: String) -> Bool {
let emailRegex = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}"
return NSPredicate(format: "SELF MATCHES %#", emailRegex).evaluateWithObject(candidate)
}
I want to make an error that gives the user an alert when email does not exist in the firebase.
I did not know how to do that.
What I did, I gave the user an alert when error != nil
Is that the right way to do it?
The firebase website has a full listing of error codes
User Authentication
The pre-defined error codes provide info on pretty much all of the errors you may receive when authenticating or handling users.
ref.resetPassword({
email: EmailTextField.text!
}, function(error) {
if (error != nil) {
if let errorCode = FAuthenticationError(rawValue: error.code) {
switch (errorCode) {
case .UserDoesNotExist:
println("Handle invalid user")
case .InvalidEmail:
println("Handle invalid email")
case .InvalidPassword:
println("Handle invalid password")
default:
println("Handle default situation")
}
}
} else {
// Success!
}
}
According to FireBase doc here it may not always be a case. Don't put it as ErrorType, change it to error. It will be NSError type. Check code of the error you get like so:
if error != nil {
if error.description == "INVALID_USER" {
// show alert that user doesn't exists
} else {
// something went wrong
}
}
}

Handling certain errors in Parse

I'm looking to create certain events when certain error codes occur in my program. For instance, if there is an error code 200, I need to let the user know they are missing the username field. Or for an error code 125, I need to let them know they did not enter a valid email address when creating for an account. How do I target these error codes specifically? I have tried the code below with no success, what am I doing wrong and is this possible?
if error.code == 125 {
var invalidEmail:UIAlertView = UIAlertView(title: Please try again, message: "That does not look like a real email address. Please enter a real one.", delegate: self, cancelButtonTitle: "Try again")
invalidEmail.show()
}
The error that xCode is telling me is that I have an unresolved identifier 'error'. There is an instance of this in the parse starter project file 'AppDelegate.swift' that calls the following code and it seems to work perfectly fine.
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
if error.code == 3010 {
println("Push notifications are not supported in the iOS Simulator.")
} else {
println("application:didFailToRegisterForRemoteNotificationsWithError: %#", error)
}
}
My code
#IBAction func signupTapped(sender: AnyObject) {
let fullname = fullnameField.text
let email = emailField.text
let username = usernameField.text
let password = passwordField.text
var user = PFUser()
user.username = username
user.password = password
user.email = email
// other fields can be set just like with PFObject
user["fullname"] = fullname
if error.code == 125 {
let alert = UIAlertController(title: "Please try again", message: "That does not look like a valid email address.", preferedStyle: .Alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
presentViewController(alert, animated: true)
}
if fullname.isEmpty || email.isEmpty || username.isEmpty || password.isEmpty {
let emptyFieldsError:UIAlertView = UIAlertView(title: "Please try again", message: "Please fill out all the fields so that we can create your account.", delegate: self, cancelButtonTitle: "Try again")
emptyFieldsError.show()
}
user.signUpInBackgroundWithBlock {
(succeeded: Bool, error: NSError?) -> Void in
if let error = error {
let errorString = error.userInfo?["error"] as? NSString
// Show the errorString somewhere and let the user try again.
} else {
// Hooray! Let them use the app now.
}
}
}
There is no error defined where you have your code. You can only reference error from inside a scope in which it exists.
user.signUpInBackgroundWithBlock {
(succeeded: Bool, error: NSError?) -> Void in
if let error = error {
let errorString = error.userInfo?["error"] as? NSString
// PUT YOUR ERROR HANDLING CODE HERE
} else {
}
}
As #Larme already pointed out, UIAlertView is deprecated, so you should use UIAlertController:
if error.code == 125 {
let alert = UIAlertController(title: "Please try again", message: "That does not look like a valid email address.", preferedStyle: .Alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
presentViewController(alert, animated: true)
}

Adding an alert to login screen Swift

For some reason I'm having trouble adding an alert to my sign in screen for when the user gets their password and username wrong. So far I have an alert for when there is only one text field filled in but when I click the sign in button if both text fields are populated no alert shows. Can someone help me with that?
#IBAction func loginButtonTapped(sender: AnyObject) {
if (self.userEmailTextField.text == "" || self.userPasswordTextField.text == "") {
var alert = UIAlertView()
alert.title = "Sign In Error"
alert.message = "You must enter a username and password"
alert.addButtonWithTitle("Dismiss")
alert.show()
return;
}
func checkLogin(username: String, password: String ) -> Bool {
if ((username == userEmailTextField) && (password == userPasswordTextField)) {
return true
} else {
return false
}
}
if (checkLogin(self.userEmailTextField.text, self.userPasswordTextField.text)) {
self.performSegueWithIdentifier("dismissLogin", sender: self)
} else {
}
I suggest you to use isEmpty property of the texts and you should use UIAlertController in swift
#IBAction func sendLogin()
{
self.view.endEditing(true)
if txtPassword.text.isEmpty || txtPassword.text.isEmpty
{
let alert = UIAlertController(
title: "Invalid Login",
message: "Please fill user and password",
preferredStyle: UIAlertControllerStyle.Alert)
let OKAction = UIAlertAction(title: "OK", style: .Default) { (action) in
// do something when user press OK button, like deleting text in both fields or do nothing
}
alert.addAction(OKAction)
presentViewController(alert, animated: true, completion: nil)
return
}
// do the login authentication process
}

Resources