Alert Blocking Segue-iOS - ios

I want to ask the user for permission (for which I am using UIAlert) before performing the segue. Once they have answered the question in the alert, I want to segue to the next View Controller, irrespective of their answer.
The code looks something like this:
showAlert() //Method showing the alert
performSegue(withIdentifier : "secondVC", sender : self)
The problem I am facing here is that the app is showing me the alert but not performing the segue.

Add a completion handler to your alert's dismiss button like this
let alert = UIAlertController(title: "Alert", message: "Content Here", preferredStyle: .alert)
// add textfield or whatever you need
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
self.performSegue(withIdentifier: "secondVC", sender: self)
}))
present(alert, animated: true)
The completion handler will be called when the user presses the "OK" button on the alert.

Related

Adding a segue to another view controller when specific action is picked from a popup

I'm trying to link a specific View Controller that will run when the user picks 'yes' off of a different pop up automatically generated after a random number is chosen.
How would I add the second view controller only when the user picks yes (and discards the pop up when the user picks no)?
I researched it on Stack already and someone suggested using Storyboard and Segues, so I have connected the first and second view controllers using "Show Segue to Weapon Pop Up View Controller", and the second VC has the storyboard ID of "PopUp".
Thanks for any help!
Here's my code:
#IBAction func rolld20(_ sender: Any) {
let randomnumber20 = Int.random(in: 1...20)
d20label.text = String(randomnumber20)
//create the alert
let d20alert = UIAlertController(title: "You rolled a D20!",
message: "You rolled a \(String(randomnumber20))! Is this enough?", preferredStyle: UIAlertController.Style.alert)
// add the actions (yes/no buttons)
d20alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.default, handler: nil)) {
//code to open up second view controller with the storyboard ID "PopUp" goes here I believe?
}
d20alert.addAction(UIAlertAction(title: "No", style: UIAlertAction.Style.cancel, handler: nil))
// show the alert when the user clicks to roll d20
self.present(d20alert, animated: true, completion: nil)
}
You need to implement performSegueWithIdentifier.
In your case, the code would be something like:
#IBAction func rolld20(_ sender: Any) {
let randomnumber20 = Int.random(in: 1...20)
let d20alert = UIAlertController(title: "You rolled a D20!",
message: "You rolled a \(String(randomnumber20))! Is this enough?", preferredStyle: UIAlertController.Style.alert)
d20alert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { (action) -> Void in
self.performSegue(withIdentifier: "PopUp", sender: nil)
}))
d20alert.addAction(UIAlertAction(title: "No", style: UIAlertAction.Style.cancel, handler: nil))
self.present(d20alert, animated: true, completion: nil)
}
I removed the comments for readability. Have in mind that the string identifier in the method is relative to the SEGUE identifier, not the destination view controller identifier. To set your segue identifier, simply click on the segue:
And edit the identifier on "Show the Attributes inspector" item:

UIAlertController not displaying immediately

I'm new to Swift programming, but can't find an answer to my problem, which is...
When I present a simple UIAlertController with a UIAlertAction handler, I am expecting the alert to display until the user responds, then the handler is executed, before continuing with the remaining code.
Unexpectedly, it seems to finish off the code block before displaying the alert and executing the handler.
I've searched Stackoverflow, and re-read the Apple Developer Documentation for UIAlertController and UIAlertAction, but I can't figure out why the code doesn't pause until the user responds.
I've tried putting the UIAlertController code in its own function, but the alert still appears to be displaying out of sequence. I'm thinking maybe there needs to be a delay to allow the Alert to draw before the next line of code executes(?).
#IBAction func buttonTapped(_ sender: Any) {
let alert = UIAlertController(title: "Ouch", message: "You didn't have to press me so hard!", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Sorry", style: .default, handler: { _ in
self.handleAlert()
}))
self.present(alert, animated: true, completion: nil)
print("Should be printed last!")
}
func handleAlert() {
print("UIAlertAction handler printed me")
}
In the code above I am expecting the debug console to display:
UIAlertAction handler printed me
Should be printed last!
But instead it displays:
Should be printed last!
UIAlertAction handler printed me
Instead of adding a seperate function, can you put it within the alert action itself like this...
let alert = UIAlertController(title: "Ouch", message: "You didn't have to press me so hard!", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Sorry", style: .default, handler: { action in
// code for action goes here
}))
self.present(alert, animated: true)
UIAlertController is designed to run asynchronously (that is why it has you pass a block of code to execute when the action is performed instead of giving a return value)
So to fix your code, put the code you want to run after an action is chosen in another function, then call that function at the end of each UIAlertAction handler.
private var currentlyShowingAlert = false
#IBAction func buttonTapped(_ sender: Any) {
if currentlyShowingAlert {
return
}
let alert = UIAlertController(title: "Ouch", message: "You didn't have to press me so hard!", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Sorry", style: .default, handler: { _ in
self.handleAlert()
self.alertCleanup()
}))
self.present(alert, animated: true, completion: nil)
currentlyShowingAlert = true
}
func handleAlert() {
print("UIAlertAction handler printed me")
}
func alertCleanup() {
print("Should be printed last!")
currentlyShowingAlert = false
}
Be careful when doing things like pushing view controllers (or anything where the calls will stack up) in direct response to a button press.
When the main thread is busy, the button can be pressed multiple times before the first buttonTapped call happens, in that case buttonTapped could be called many times in a row, currentlyShowingAlert will prevent that issue.

How to show alert after unwind transition in iOS?

I'm implementing Login in iOS. I want to unwind to the previous VC(IntroVC) first, and to show completed sign up alert about completed in IntroVC.
(completingSignUp is Unwind function.)
#IBAction func completingSignUp(_ segue: UIStoryboardSegue) {
let completedAlert = UIAlertController(title: "Completing", message: "Congratulations.", preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default, handler: nil)
completedAlert.addAction(ok)
self.present(completedAlert, animated: true)
}
It shows only the alert without unwind to IntroVC.
I think the location of the alert code seems to be incorrect.
Where should I write alert code?
Put the code into IntroVC‘s viewDidAppear. You will need to introduce a condition so that the alert is presented only when you are coming back via the unwind segue.

How to prevent viewing a view when clicking on a button (Swift)

I'm having a button on view that contains this condition:
FIRAuth.auth()?.addStateDidChangeListener { auth, user in
if let user = user {
self.performSegue(withIdentifier: "AddDevice", sender: nil)
}
else {
let alert = UIAlertController(title: "Sorry", message:"You Have to register", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default) { _ in })
self.present(alert, animated: true){}
}
}
To check whether the user is logged in or not!
If logged in the segue should run and open the next view
If not an alert should appear to the user.
But the next view contains a function that retrieved the current user data! (Logged in user) in viewDidLoad function!
So when the user not logged in and I click to this button I keep getting crash instead of the alert!
How can I prevent viewing the next view and just present the alert!
So I can avoid the crash?
From your description is sounds like the segue is always executing, but it's not what you want.
Connect the segue from the view controller itself, name it and put the whole method inside IBAction connected to the button.
Something like this:
#IBAction func loginDidTouch(sender: AnyObject) {
FIRAuth.auth()?.addStateDidChangeListener { auth, user in
if let user = user {
self.performSegue(withIdentifier: "AddDevice", sender: nil)
}
else {
let alert = UIAlertController(title: "Sorry", message:"You Have to register", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default) { _ in })
self.present(alert, animated: true){}
}
}
For illustration:
In the first image the segue is connected to the button. Therefore, every time the button is pressed it will execute the segue.
In the second image the segue is connected to the view controller and the button is only connected to the via the IBAction. Therefore, the button only triggers the action and the action triggers the segue.
This could easily checked by selecting the segue in storyboard

Issues with displaying Alerts in Swift (After clicking "Ok", it unwinds segue

I wrote the following function below to display alerts through my project. Every time i check for an error in a form i display the alert when the user clicks submit. I want to simply show the alert, but not unwind the pervious segue. I want to stay at the current screen and give the user the opportunity to complete the form. Right now when the user clicks submit, it displays the alert ..but when i click the ok button to dismiss the alert it immediately unwinds the segue to the previous screen.
I have included the UIAlertViewDelegate in the class.... any ideas why this might be happening?
func displayAlert(title:String, error:String) {
var alert = UIAlertController(title: title, message: error, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: { action in
self.dismissViewControllerAnimated(true, completion: nil)
}))
self.presentViewController(alert, animated: true, completion: nil)
}
Never mind.
func displayAlert(title:String, error:String) {
var alert = UIAlertController(title: title, message: error, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: { action in
//comment out this line and it will still work. It will not segue back to the previous screen.
//self.dismissViewControllerAnimated(true, completion: nil)
}))
self.presentViewController(alert, animated: true, completion: nil)
}

Resources