UIAlertController creation in global method [duplicate] - swift

This question already has answers here:
Swift writing a function that takes self as an input
(1 answer)
How to create uialertcontroller in global swift
(12 answers)
Closed 5 years ago.
I have a few four lines blocks as below in my app to decide flow based on user's Yes or No action
let alert = UIAlertController(title: "Delete", message: "Really delete?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Yes", style: .destructive, handler: {(action) in self.deleteHistoryRecord(forRecordID: self.shistIDs[indexPath.row])}))
alert.addAction(UIAlertAction(title: "No", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
I'd like to create global app method/function with first three lines and returning Yes/No flag back. What's the best way to manage hander closure to call proper method in caller?

In order to have a global function able to show the alert, you might use an extension like this one:
extension UIViewController {
func showAlert(_ completion:#escaping ()->()) {
let alert = UIAlertController(title: "Delete", message: "Really delete?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Yes", style: .destructive, handler: { (action) in
completion()
}))
alert.addAction(UIAlertAction(title: "No", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
and then whenever you need to show the alert you just call showAlert passing the completion you would like to be executed (in case of Yes); eg: from your ViewController you might use this:
self.showAlert {
self.deleteHistoryRecord(forRecordID: self.shistIDs[indexPath.row])
}

Related

variable 'alert' is written to, but never read

I have an alert-box, which returns a number of warnings that I'm having trouble, getting rid of.
let alert = UIAlertController(title: "Delete the group?", message: "The group is removed permanently", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { [weak alert] (_) in
self.dismiss(animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
// Perform the serverside action here and dismiss
}))
self.present(alert, animated: true, completion: nil)
Both addAction-lines returns a "Variable 'alert' is written to, but never read"-warning. I don't understand, since I use it in the "present"-line in the same scope.
Any ideas?
I have all my alerts in a separate class like so;
class AlertViewController {
func someAlert(with title: String?, message: String?, viewController: UIViewController) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let someAction = UIAlertAction(title: "Action Title", style: .default) { (_) in
//Perform your action here
}
alertController.addAction(someAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
viewController.present(alertController, animated: true, completion: nil)
}
}
If you use the style: .cancel it will automatically dismiss the alert. Furthermore, as a better UX, including this .cancel will allow the user to tap anywhere on the view to dismiss the alert as well.
You can call this action where needed like so;
AlertViewController.someAlert(with: "Title", message: "Message", viewController: self)
Self is the UIViewController you wish to present upon.

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)

Method using the calling object's "self" by default

I have a utility class containing functions that are used by multiple other classes. One of those is an alert function:
class Utils {
func doAlert (title: String, message: String, target: UIViewController) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Close", style: .cancel, handler: nil))
target.present(alert, animated: true, completion: nil)
}
}
This function will always target self on the view controller, so I'd like to not have to add target: self every time I call the function, but I can't just set it as a default value since that causes it to refer back to the Utils class. Is there any way I can rewrite this to avoid that?
Utility classes are an antipattern exactly for this reason, what you really want to use is an extension:
extension UIViewController {
func doAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Close", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
and then you can call the method directly on all your controllers:
self.doAlert(title: "title", message: "message")
In general avoid classes with utility methods. Try to add methods to the types to which the functionality actually belongs.
Instead of putting the function in your Utils class, you could put it in an extension to UIViewController, like this:
extension UIViewController {
func doAlert (title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Close", style: .cancel, handler: nil))
target.present(alert, 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
}