I have found myself repeatedly writing the following lines of code
let alert = UIAlertController(title: "Something went wrong", message: "This is why something went wrong", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true)
And then I would populate the titles and message of the alert and buttons from NSError objects. In search of a better, more efficient way I came across Apple's Error Handling Programming Guide, which seemed promising:
Note: Beginning with OS X version 10.4, you can use the alertWithError:class method of NSAlert as a convenience for creating NSAlert objects to use when displaying alert dialogs or sheets. The method extracts the localized information from the passed-in NSError object for its message text, informative text, and button titles. You may also use the presentError: message to display error alerts.
The NSError class contains properties specifically meant to be displayed in an alert view (at least for OS X). Unfortunately, I was not able to find a similar approach for iOS.
Is there an easy, convenient way to display Error objects in an Alert in iOS?
Write your own extension to UIAlertController:
extension UIAlertController {
func alert(with error: Error) -> UIAlertController {
// Create and setup the alert as needed using the error
var res = UIAlertController(title: "Something went wrong", message: "Some message", preferredStyle: .alert)
res.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
return res
}
}
Update the parameter to use NSError if desired and/or add additional parameters as needed to suit your needs.
Then you can use it as follows:
let alert = UIAlertController.alert(with: someError)
self.present(alert, animated: true)
Is there an easy, convenient way to display Error objects in an Alert in iOS?
UIAlertController does not have a convenient (auto-parsing) way to display an Error/NSError atm. UIKit does not provide any, so you will end up with a custom solution.
NSError has localizedDescription property which can be shown in UIAlertController's message as follow,
let alert = UIAlertController(title: "Something went wrong", message: error.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true)
Related
I have an app with a large number of ViewControllers. There is also a collection of functions that return UIAlertControllers informing the user regarding events related to his account.
Here is an example of one such funtion:
func signInSuccessAlert() -> UIAlertController {
//signInSuccessAlert
let signInSuccessAlert = UIAlertController(title: "Success", message: "You have been successfully signed in!", preferredStyle: .alert)
signInSuccessAlert.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
return signInSuccessAlert
}
My goal is to then be able to display these UIAlertControllers in one line. Like so:
present(signInSuccessAlert(), animated: true, completion: nil)
What is the best way to make these functions available only to the ViewControllers that need them? As opposed to declaring them globally.
You could create an extension of UIViewController and declare all those functions there.
Something like this:
extension UIViewController
{
func signInSuccessAlert() -> UIAlertController {
//signInSuccessAlert
let signInSuccessAlert = UIAlertController(title: "Success", message: "You have been successfully signed in!", preferredStyle: .alert)
signInSuccessAlert.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
return signInSuccessAlert
}
}
This way all your viewcontrollers will have access to these functions. If you want want to give access only to some viewcontrollers you will have to use protocols like AgRizzo suggested in the comment.
I'm trying to show two UIAlertController's instances continuously, which is like this code block below.
func showAlerts() {
let alertA = UIAlertController(title: "Alert A", message: "This is alert a...", preferredStyle: .alert)
let alertB = UIAlertController(title: "Alert B", message: "This is alert b...", preferredStyle: .alert)
let alertButton1 = UIAlertAction(title: "OK", style: .default, handler: nil)
let alertButton2 = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertA.addAction(alertButton1)
alertA.addAction(alertButton2)
alertB.addAction(alertButton1)
alertB.addAction(alertButton2)
self.present(alertA, animated: true) {
self.present(alertB, animated: true, completion: {
debugPrint("alerts are all shown")
})
}
}
I expect this code to show each alert continuously, which means alertB shows after alertA. But alertB doesn't appear as I expect, with warnings on console saying;
Warning: Attempt to present <UIAlertController: 0x7f7ffde0ace0> on <ContinuousUIAlertController_Experiment.ViewController: 0x7f7ffdd092d0> which is already presenting <UIAlertController: 0x7f7ffde09f90>
If I remember correctly, multiple UIAlertController objects cannot be existed at the same time. So I somehow understand what the warning above tells.
So, then, how can I implement continuous alert showing using completion of UIViewController::present(_:animated:completion:) or with nearly the same logic? (I prefer not to use UIAlertAction's handler)
If there is a solution, please let me know.
I'm struggling with this problem for a few days and I've not addressed yet.
You can't show 2 uialettcontrol at 1time.
But you can show 2nd uialettcontrol on 1st one's uialeraction.
For example
let alertController = UIAlertController(title: "iOScreator", message:
"Hello, world!", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Destructive,handler: { action in
self.pressed()
}))
func pressed()
{
print("you pressed")
}
On pressed event you can write code for 2nd uialettcontrol.
I am currently trying to create a class that will simplify the process of defining an UIAlert.
As the traditional way of initializing an alert is
let alert = UIAlertController(title:"hello world", message: "how are you",preferedStyle: .actionSheet)
let ok = UIAlertAction(title:"ok",style:.default,handler: {(action) -> Void in print("ok")})
alert.addAction(ok)
self.presentViewController(alert,animated:true,completion:nil)
However, as i am going to be having the same format of alert in alot of places through out my app, I was thinking of making a single class that contains my entire alert object with all actions added so i can simply do:
let alert = MyAlert()
self.presentViewController(alert,animated:true,completion:nil)
I have
class myAlert: UIAlertController{
init() {
super.init(title:"hello world", message: "how are you", preferredStyle: .actionSheet)
}
}
But I seem to be getting an error "Must call a designated initliazer of the superclass 'UIAlertController'
Can you explain to me what I am doing wrong and send me in the right direction. I am fairly new to swift so any help is much appreciated. Thank you
You could just create an extension and whenever you want to display a UIAlertController, just call the method. With an extension, it can be used throughout your app.
extension UIViewController {
func displayMessageAlert(withAlertTitle alertTitle: String, andMessage message: String) {
let alert = UIAlertController(title: alertTitle, message: message, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .destructive, handler: nil)
alert.addAction(okAction)
self.present(alert, animated: true, completion: nil)
}
}
Usage on a UIViewController:
self.displayMessageAlert(withAlertTitle: "Your Title", andMessage: "Display your message here.")
I'm a beginning swift developer, so bear with me here.
I have a multiplayer game app, and from my server (yes, this is a background thread) I receive a signal that a match has been found. Then this snippet is executed
dispatch_async(dispatch_get_main_queue(), {
print("showing dialog")
let dialog = UIAlertController(title: "Game found", message: "You are playing with a person named "+self.player2.getName(), preferredStyle: UIAlertControllerStyle.Alert)
dialog.addAction(UIAlertAction(title: "cancel", style: UIAlertActionStyle.Cancel, handler: nil))
self.presentViewController(dialog, animated: true, completion: nil)
self.labelOpponentName.text = self.player2.getName()
})
However, I get the following error
Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (<UIAlertController: 0x79151e00>)
Also, my labelOpponentName is not updating it's text. Why is that?
There may be another UIAlertController defined inside your function or globally.
dispatch_async(dispatch_get_main_queue(), {
print("showing dialog")
let dialog = UIAlertController(title: "Game found", message: "You are playing with a person named "+self.player2.getName(), preferredStyle: UIAlertControllerStyle.Alert)
dialog.addAction(UIAlertAction(title: "cancel", style: UIAlertActionStyle.Cancel, handler: nil))
self.presentViewController(dialog, animated: true, completion: nil)
self.labelOpponentName.text = self.player2.getName()
})
I'm trying to make a UIAlertView on my Parse app but for some reason every time I run it, it crashes and I'm taken to ApplicationDelegate where I get a SIGABRT. Here is my alert code, I'm pretty sure I'm not doing anything wrong because it's worked before... Is it because I'm loading data into a tableview from Parse?
func displayAlert(title: String, message: String) {
var alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
}))
presentViewController(alert, animated: true, completion: nil)
}
Not sure what your issue is. You could simplify the code as follows (Xcode 7b6) by eliminating the empty closure and shortening the arguments when possible. But I don't think this is your problem. Instead, you should show the code where you call this function.
var alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
presentViewController(alert, animated: true, completion: nil)