Access input from UIAlertController - swift

I've got a UIAlertController which is prompted to the user when they choose "Enter Password" on the TouchID screen. How do I recover the user's input after presenting this on screen?
let passwordPrompt = UIAlertController(title: "Enter Password", message: "You have selected to enter your passwod.", preferredStyle: UIAlertControllerStyle.Alert)
passwordPrompt.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Default, handler: nil))
passwordPrompt.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
passwordPrompt.addTextFieldWithConfigurationHandler({(textField: UITextField!) in
textField.placeholder = "Password"
textField.secureTextEntry = true
})
presentViewController(passwordPrompt, animated: true, completion: nil)
I know the OK button should probably have a handler, but right now this code doesn't really do anything, but I want to display the output of the text field through a println. This is really just a test app for me to learn Swift and some new API stuff.

I've written up a blog post exploring the new API. You can just capture a local variable in the closure and you're good to go.
var inputTextField: UITextField?
let passwordPrompt = UIAlertController(title: "Enter Password", message: "You have selected to enter your password.", preferredStyle: UIAlertControllerStyle.Alert)
passwordPrompt.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Default, handler: nil))
passwordPrompt.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
// Now do whatever you want with inputTextField (remember to unwrap the optional)
}))
passwordPrompt.addTextFieldWithConfigurationHandler({(textField: UITextField!) in
textField.placeholder = "Password"
textField.secureTextEntry = true
inputTextField = textField
})
presentViewController(passwordPrompt, animated: true, completion: nil)
That way you avoid having an unnecessary property on your view controller.

I know comments have been posted to answer the question, but an answer should make the solution explicit.
#IBOutlet var newWordField: UITextField
func wordEntered(alert: UIAlertAction!){
// store the new word
self.textView2.text = deletedString + " " + self.newWordField.text
}
func addTextField(textField: UITextField!){
// add the text field and make the result global
textField.placeholder = "Definition"
self.newWordField = textField
}
// display an alert
let newWordPrompt = UIAlertController(title: "Enter definition", message: "Trainging the machine!", preferredStyle: UIAlertControllerStyle.Alert)
newWordPrompt.addTextFieldWithConfigurationHandler(addTextField)
newWordPrompt.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Default, handler: nil))
newWordPrompt.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: wordEntered))
presentViewController(newWordPrompt, animated: true, completion: nil)
This displays a prompt with a text field and two action buttons. It reads the text field when done.

Do this inside your closure:
let tf = alert.textFields[0] as UITextField
Here is a gist

I ported Ash Furrow's answer to Swift 3.
var inputTextField: UITextField?
let passwordPrompt = UIAlertController(title: "Enter Password", message: "You have selected to enter your password.", preferredStyle: UIAlertControllerStyle.alert)
passwordPrompt.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.default, handler: nil))
passwordPrompt.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: { (action) -> Void in
// Now do whatever you want with inputTextField (remember to unwrap the optional)
}))
passwordPrompt.addTextField(configurationHandler: {(textField: UITextField!) in
textField.placeholder = "Password"
textField.isSecureTextEntry = true
inputTextField = textField
})
present(passwordPrompt, animated: true, completion: nil)

Related

Adding TextField to AlertController breaks AlertController

I am currently trying to open up an AlertController with a TextField inside. When running
let configAlert = UIAlertController(title: "Configure Add-On", message: "Enter Your Add-On Name:", preferredStyle: UIAlertControllerStyle.alert)
configAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action: UIAlertAction!) in
// Handle Input
}))
present(configAlert, animated: true, completion: nil)
everything works fine, but as soon as I add the TextField
configAlert.addTextField { (textField) in
textField.placeholder = "Name"
}
the Alert takes about 10 times longer to open, instantly dismisses, and I get this error in the console spammed about 30 times:
2017-11-26 13:04:08.985783-0500 MinelyMod[380:14792] Warning: Attempt to dismiss from view controller <UISplitViewController: 0x147e0a6a0> while a presentation or dismiss is in progress!
Here is the completed AlertController thats failing
let configAlert = UIAlertController(title: "Configure Add-On", message: "Enter Your Add-On Name:", preferredStyle: UIAlertControllerStyle.alert)
configAlert.addTextField { (textField) in
textField.placeholder = "Name"
}
configAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action: UIAlertAction!) in
// Handle Input
}))
present(configAlert, animated: true, completion: nil)
let alertController = UIAlertController(title: "Title", message: "", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Save", style: .default, handler: {
alert -> Void in
let textField = alertController.textFields![0] as UITextField
// do something with textField
}))
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
alertController.addTextField(configurationHandler: {(textField : UITextField!) -> Void in
textField.placeholder = "Search"
})
self.present(alertController, animated: true, completion: nil)

UIAlertController - Order of actions [duplicate]

This question already has answers here:
Unable to choose order of buttons in UIAlertController
(2 answers)
Closed 5 years ago.
I wanna show alert window by pressing on button. Usual thing. But I'm confused that I try to show button "Awesome" at first, but always "Cancel" button stay the first. How can I fix it?
let alert = UIAlertController(title: "Hello world", message: "Testing", preferredStyle: .alert)
let action = UIAlertAction(title: "Awesome", style: .default){(_) in print("Awesome")}
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alert.addTextField(configurationHandler: nil)
alert.addAction(action)
alert.addAction(cancel)
alert.actions.forEach( { (action) in print( action.title! ) } )
present(alert, animated: true, completion: nil)
Irregular order of buttons
Changing the order will not work as default position of cancel button is left.
Change the action style for cancel button type to UIAlertActionStyleDefault instead of UIAlertActionStyleCancel.
Try like this, it will work for you.
let alertController = UIAlertController(title: "", message: "", preferredStyle: UIAlertControllerStyle.alert)
let destructiveAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.default) {
(result : UIAlertAction) -> Void in
}
let okAction = UIAlertAction(title: "Awesome", style: UIAlertActionStyle.default) {
(result : UIAlertAction) -> Void in
}
alertController.addAction(destructiveAction)
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: nil)

Cannot call value of non-function type UIAlertAction

I'm not sure what's wrong with this function. I'm trying to present an alert asking if the user would like to delete the selected photo.
If the function that deletes the photo returns an error, I would like to show that error to the user.
Xcode is failing on the errorController.addAction line with the message that "cannot call value of non-function type UIAlertAction"
I'm using Swift 2
#IBAction func deletePhoto(sender: AnyObject) {
let alertController = UIAlertController(title: "Delete Photo", message: "Are you sure you want to delete this photo?", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "OK", style: .Default) { UIAlertAction in
self.photoGateway!.delete(self.photo!.id!, completion: { (withError: Bool) -> Void in
if (withError == true) {
let errorController = UIAlertController(title: "Delete Failed", message: "blah", preferredStyle: UIAlertControllerStyle.Alert)
// The next line is causing the error
errorController.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(errorController, animated: true, completion: nil)
} else {
self.dismissViewControllerAnimated(true, completion: nil)
}
})
}
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { UIAlertAction in
print("Cancelled")
}
alertController.addAction(okAction)
alertController.addAction(cancelAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
If I take out the offending line then all works well, just the user has no way of dismissing the alert
Fixed it. Changed:
errorController.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
to:
errorController.addAction(UIKit.UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
The reason this is happening is because the parameter for your callbacks is called UIAlertAction (lines 3 and 20 above) and this is overriding the declaration in UIKit. This is likely a mistake of code-completion. Just rename it to action or something like that or just _ as you don't reference it.

UIAlertController --> Used to update variable?

I'm new to Xcode and Swift. I'm trying to set up an alert (which I have done - code below). I was wondering if someone can help me out. What I would like to do is reset two different variables to 0 if "Yes" is tapped.
Your help is greatly apprecieated.
#IBAction func showAlert() {
let alertController = UIAlertController(title: "Confirm Point Reset", message: "Are You Sure?", preferredStyle: .Alert)
let firstAction = UIAlertAction(title: "Yes", style: .Default, handler: nil)
let secondAction = UIAlertAction(title: "No", style: .Default, handler: nil)
alertController.addAction(firstAction)
alertController.addAction(secondAction)
presentViewController(alertController, animated: true, completion: nil)
}
You need to add the completion handler and update the values in that closure. The completion handler is the code that is executed when the action occurs (when the button is pressed).
let firstAction = UIAlertAction(title: "Yes", style: .Default) { action in
self.foo = 0
}

Can a UIAlertAction trigger a function?

Is it possible to connect a function to an UIAlertAction?
So after a user clicks the OK button it performs an action? Isn't this what the handler parameter does?
let alert: UIAlertController = UIAlertController(title: "Email already registered", message: "Please enter a different email", preferredStyle: .alert)
let okButton = UIAlertAction(title: "OK", style: .default, handler: backToLogin())
alert.addAction(okButton)
self.presentViewController(alert, animated: true, completion: nil)
...
func backToLogin() {
self.performSegueWithIdentifier("toLoginPage", sender: self)
}
You can use a function as the handler, but it needs to have the correct type. Also you must not call it when you pass it as an argument, i.e., instead of handler: backToLogin() (which would set the return value of backToLogin as the handler) you would have handler: backToLogin without the ().
The following should work:
func backToLogin(alertAction: UIAlertAction) {
self.performSegueWithIdentifier("toLoginPage", sender: self)
}
let okButton = UIAlertAction(title: "OK", style: .Default, handler: backToLogin)
But having to change backToLogin might defeat the purpose, so you could just use a closure:
let okButton = UIAlertAction(title: "OK", style: .Default) { _ in
self.backToLogin()
}
You need to enter the handler
let okButton = UIAlertAction(title: "OK", style: .Default, handler: {
(UIAlertAction) in
self.backToLogin()
})
}
See this answer for more info: Writing handler for UIAlertAction