Show two UIAlertController objects continuously using completion block - ios

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.

Related

Attempting to create an object to act as an UIAlertController wrapper

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.")

UIAlertAction's handler doesn't work

I'm new to swift and now following a tutorial book. The book is kind outdated, and I had this bug.
Basically I'm trying to do a table cell selection, after I selected the cell it should pop up a menu and then I can hit the call button. However, right now after I hit the call button, the expected alter box doesn't show up, and the compiler gives me the error: Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior
There is no bug when I edit the code, it just doesn't run correctly.
Another problem is that I have about 17 rows on the table, the stimulator's screen only shows 7 and I can't scroll down to see the rest of them.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath:NSIndexPath){
//this creates an option menu when you tap on the row
let optionMenu = UIAlertController(title: nil, message: "What do you want to do?", preferredStyle: .ActionSheet)
//this is what happened after you hit the cancel option
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
//defines the action after tap on the call option
let nocallAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
let callActionHandler = {(action:UIAlertAction!)-> Void in
let alertMessage = UIAlertController(title: "Service Unavaliable", message: "Sorry, the call is not avaliable yet, please retry later.", preferredStyle: .Alert)
alertMessage.addAction(nocallAction)
}
//this is what happened after you hit the call option
let callAction = UIAlertAction(title: "Call " + "123-000-\(indexPath.row)", style:
UIAlertActionStyle.Default, handler: callActionHandler)
//this is what happened after you hit the been there option
let isVisitedAction = UIAlertAction(title: "I've been here", style: .Default, handler: {
(action:UIAlertAction!) -> Void in
let cell = tableView.cellForRowAtIndexPath(indexPath)
cell?.accessoryType = .Checkmark
})
//add the action to the option menu
optionMenu.addAction(isVisitedAction)
optionMenu.addAction(callAction)
optionMenu.addAction(cancelAction)
self.presentViewController(optionMenu, animated: true, completion: nil)
}
You never present the view controller in the callActionHandler - it should look like this:
let callActionHandler = {(action:UIAlertAction!)-> Void in
let alertMessage = UIAlertController(title: "Service Unavaliable", message: "Sorry, the call is not avaliable yet, please retry later.", preferredStyle: .Alert)
alertMessage.addAction(nocallAction)
self.presentViewController(alertMessage, animated: true, completion: nil)
}
Swift also allows you to create the completion handler at the same time as the UIAlertAction, which I think is more readable:
let callAction = UIAlertAction(title: "Call " + "123-000-243534", style: UIAlertActionStyle.Default)
{ action in
let alertMessage = UIAlertController(title: "Service Unavaliable", message: "Sorry, the call is not avaliable yet, please retry later.", preferredStyle: .Alert)
alertMessage.addAction(nocallAction)
self.presentViewController(alertMessage, animated: true, completion: nil)
}

Attempt to present <UIAlertController: 0x79151e00> on <Prisoners_Dillema.ControllerGame: 0x788b1a00> whose view is not in the window hierarchy

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()
})

UIAlertView Crashes App

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)

Show alert in AppDelegate in Swift [duplicate]

This question already has answers here:
How to show UIAlertController from Appdelegate
(6 answers)
Closed 4 years ago.
I try the next code snippet:
var alert = UIAlertController(title: "Alert", message: "Cannot connect to : \(error!.localizedDescription)", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))
self.window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)
in my AppDelegate, but it prints me the next error in console:
Warning: Attempt to present <UIAlertController: 0x7ff6cd827a30> on <Messenger.WelcomeController: 0x7ff6cb51c940> whose view is not in the window hierarchy!
How can I fix this error?
This is what i'm using now to do that.
var alertController = UIAlertController(title: "Title", message: "Any message", preferredStyle: .ActionSheet)
var okAction = UIAlertAction(title: "Yes", style: UIAlertActionStyle.Default) {
UIAlertAction in
NSLog("OK Pressed")
}
var cancelAction = UIAlertAction(title: "No", style: UIAlertActionStyle.Cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
}
alertController.addAction(okAction)
alertController.addAction(cancelAction)
self.window?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)
Swift 5:
let alert = UIAlertController(title: "Test", message:"Message", preferredStyle: UIAlertController.Style.alert)
// add an action (button)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
// show the alert
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
As per Jorge's answer, updated for Swift 4
let alertController = UIAlertController(title: "Title", message: "Message", preferredStyle: .actionSheet)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
UIAlertAction in
NSLog("OK Pressed")
}
let cancelAction = UIAlertAction(title: "CANCEL", style: UIAlertActionStyle.cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
}
alertController.addAction(okAction)
alertController.addAction(cancelAction)
self.window?.rootViewController?.present(alertController, animated: true, completion: nil)
Swift 3.0 or above, Working in all condition , like in case of tab bar, in case of presented view etc ..
let alert = UIAlertController(title: "Test", message:"Message", preferredStyle: UIAlertControllerStyle.alert)
// add an action (button)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
// show alert
let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert + 1;
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alertController, animated: true, completion: nil)
I had the similar problem.
I have fixed it by presenting UIAlertController in Main Queue.
Code Looks like following.
let alert = UIAlertController(title: "My Title", message: "My Message", preferredStyle: .alert)
let actionYes = UIAlertAction(title: "Yes", style: .default, handler: { action in
print("action yes handler")
})
let actionCancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { action in
print("action cancel handler")
})
alert.addAction(actionYes)
alert.addAction(actionCancel)
DispatchQueue.main.async {
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
}
Have you tried using UIApplication.shared.keyWindow?.rootViewController?.present(...) ?
I suppose you are calling that code snippet from the applicationDidFinishLunchingWithOptions.
I tried it as a matter of fact because I had to. The thing is: what you are trying to do is correct but the ViewController that the AppDelegate makes and presents is about to be put on screen and before that, the code snippet tries to create an alertView and put in on top of non existent View of the RootViewController.
What I would do is move it to another delegate call which is guaranteed to be called after the RootViewController is presented.
func applicationDidBecomeActive(application: UIApplication) {
//This method is called when the rootViewController is set and the view.
// And the View controller is ready to get touches or events.
var alert = UIAlertController(title: "Alert", message: "Cannot connect to :", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))
self.window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)
}
But as always know the responsibility of the AppDelegate. It is to handle the application lifecycle and application wide delegate calls and events. If putting code here makes sense, then do it. But if you will be better off putting the code on the rootViewController or other parts then think about it too.
Anyway, hope it helps. Cheers!
I would suggest NOT doing this in the AppDelegate. The App Delegate it intended to handle Delegate functions from the OS rather than implementing things like alert views.
If you are wanting to present an alert view here to be shown at the start of the app I would do this by implementing it in your first view controller.

Resources