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.
Related
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.
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:
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.
I'm creating an app that displays users comments. User enters a comment and then clicks submit button and then an alert action view should occur. I'm trying to direct a user to my fourthviewcontroller when the ok button in the alert view is clicked. Here is my code, it should work fine.
let alert = UIAlertController(title: "Succesful", message: "Successfully added!", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
let uivc = self.storyboard!.instantiateViewController(withIdentifier: "ViewController")
self.navigationController!.pushViewController(uivc, animated: true)
}))
self.present(alert, animated: true)
However, I get this error when I click on the OK button.
'InvalidPathValidation', reason: '(child:) Must be a non-empty string and not contain '.' '#' '$' '[' or ']''
FourthViewController is created based on the user's selections on the past three viewcontrollers. There is a unique fourthviewcontroller based on the combination of the tableview cells clicked in the previous view controllers. I believe the problem arises because when I direct the user to FourthViewController, the app does not know what the FourthViewController contains as there were no tableview cells clicked before. When I change the direction of the VC from FourthViewController to FirstViewController everything works amazingly.
Is it possible to fix this issue? I'd appreciate any help! Thank you very much and have a good day!
If I understood correctly, the FourthViewController has some variables which depend on the previous ViewControllers. In that case just initialise these variables setting their value: uivc.varName = value
You may also perform a segue instead of instantiating the view controller and you can set the values of the nextViewController in the prepare function.
Remove following line form action completion
let uivc = self.storyboard!.instantiateViewController(withIdentifier:"ViewController")
self.navigationController!.pushViewController(uivc, animated: true)
and make a function as below
func navigate(){
let uivc = self.storyboard!.instantiateViewController(withIdentifier:"ViewController")
self.navigationController!.pushViewController(uivc, animated: true)
}
now add following in action completion
self.navigate()
like below
let alert = UIAlertController(title: "Succesful", message: "Successfully added!", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
self.navigate()
}))
self.present(alert, animated: true)
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