How to get back to viewcontroller in alertview - swift

I tried to get back to the viewcontroller when user press Go home in the alertView and it show me the error ( libc++abi.dylib: terminating with uncaught exception of type NSException )
#IBAction func roundButton(sender: AnyObject) {
//add alert
alertController = UIAlertController(title: "Return Home", message: "Are you sure???", preferredStyle: .Alert)
let alertAction1 = UIAlertAction(title: "Cancel", style: .Default) { (action) in
}
let alertAction2 = UIAlertAction(title: "Go Home", style: .Destructive) { (action) in
let nv = self.storyboard!.instantiateViewControllerWithIdentifier("storyboardidentifier") as! ViewController
self.presentViewController(nv, animated:true, completion:nil)
}
alertController?.addAction(alertAction2)
alertController?.addAction(alertAction1)
self.presentViewController(alertController!, animated: true, completion: nil)
//end alert
}

Since you didn't provide much information, there are a lot of possibilities. I will try to cover most of them.
Let's say that you are presenting the alert in BViewController. And you want to get back to AViewController.
If AViewController and BViewController are embedded in a UINavgationController, you will have to connect an unwind segue between BViewController and AViewController.
First, in AViewController, add this method:
#IBAction func unwind(segue: UIStoryBoardSegue) {
}
In the storyboard, control-drag from BViewController to the "Exit" of `AviewController and select "unwind:" aka the method you just declared. This is what you should see
Now give the segue you just added an identifier, say "unwindToHome".
In the UIAlertAction call back closure, initiate the segue:
self.performSegueWithIdentifier("unwindToHome", sender: self)
And that's it!
If you are presenting the BViewController modally, then things are simpler, just call dismissViewControllerAnimated:
self.dismissViewControllerAnimated(true, completion: nil)

Create a segue on your storyboard between the two view controllers and give it an Identifier, then, on the completion handler of your alert action, you can trigger the segue. Something along the lines of:
let alertAction2 = UIAlertAction(title: "Go Home", style: .Destructive) { (action) in
self.performSegueWithIdentifier("MyStoryboardSegue", sender: self)
}
Good luck!

Related

AlertController trying to be presented on view not in window hierarchy

Trying to figure out why I am getting this error. I have a single view application with two viewcontrollers. I have a segue to the second vc on a button touch:
#IBAction func showAccount(_ sender: Any) {
performSegue(withIdentifier: "toAccountFromRoot", sender: self)
}
I have a facade pattern set up with a Controller file and several helper files. I set the Controller up on the AccountViewController file:
let myController = Controller.sharedInstance
One of the helper files is to set up a central AlertController for simplified alerts (no extra buttons). It has one method, presentAlert that takes a few arguments, alert title, messsage, presenter.
On my AccountViewController I am attempting to present an alert using this code:
myController.alert.presentAlert("No Agent", "You have not registered an agent yet.", self)
and in the AlertManager file, presentAlert looks like this:
func presentAlert(_ title:String, _ message:String, _ presenter:UIViewController) {
let myAlert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
myAlert.addAction(okAction)
presenter.present(myAlert, animated:true, completion:nil)
}
I've done this in quite a few apps without an issue so I am confused as to why the compiler thinks the AccountViewController view is not in the window hierarchy.
Dang it, typed all that and then I solved it 5 seconds later. Just in case someone else runs into the same problem, I was trying to present the alert in viewDidLoad, should of been doing it in viewDidAppear.

ViewController segue and login

I'm new to Swift (and programming in general). I'm having some difficulties in Xcode with the login feature. What I want is that the user should be logged in if no errors was returned and the user should be sent to another controller. I've read some of the documentation from Apple and the performSegueWithIdentifier (and of course some questions asked here), but it still does not work when I use a segue with push or modal that are given an identifier. Either the app crashes, or the user is sent to my UITabBarController even if the credentials was incorrect.
This is my LogInViewController.swift:
#IBAction func loginAction(sender: AnyObject)
{
if self.emailField.text == "" || self.passwordField.text == ""
{
let alertController = UIAlertController(title: "Oops!", message: "Please enter an email and password.", preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
else
{
FIRAuth.auth()?.signInWithEmail(self.emailField.text!, password: self.passwordField.text!) { (user, error) in
if error == nil
{
self.emailField.text = ""
self.passwordField.text = ""
}
else
{
let alertController = UIAlertController(title: "Oops!", message: error?.localizedDescription, preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
// User Logged in
self.performSegueWithIdentifier("LoggedIn", sender: self)
}
}
}
The error I get in the console:
2016-09-04 14:55:30.019 DrinkApp[37777:1006336] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Could not find a navigation controller for segue 'LoggedIn'. Push segues can only be used when the source controller is managed by an instance of UINavigationController.'
There are two main ways to send a user to another View Controller. The first is performSegueWithIdentifier. Here's how you would go about using that:
First of all, control-drag from the yellow circle of the original VC to the target VC in the interface builder.
Next, click on the 'segue arrow' that appears between the two View Controllers.
In the identifier field, type in mySegue.
Next, go back to your code. When you reach the sign in section, add the following code:
self.performSegueWithIdentifier("mySegue", sender: nil)
The second method is a bit more advanced. Here's how that would work:
First, click on the yellow circle of the destination VC. Click on the newspaper, then call the storyboard ID myVC.
Make sure to click on Storyboard ID
Go back to the same part of the code and copy and paste this code:
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initViewController: UIViewController = storyboard.instantiateViewControllerWithIdentifier("myVC") as UIViewController
self.presentViewController(initViewController, animated: true, completion: nil)
Comment down below if you have any questions. Good luck!
Here is a Firebase login example:
func login() {
FIRAuth.auth()?.signInWithEmail(textFieldLoginEmail.text!, password: textFieldLoginPassword.text!) { (user, error) in
if error != nil {
let alert = UIAlertController(title: "User Authentication error",
message: error?.localizedDescription,
preferredStyle: .Alert)
let OKAction = UIAlertAction(title: "OK",
style: .Default) { (action: UIAlertAction!) -> Void in
}
let resetPasswordAction = UIAlertAction(title: "OK",
style: .Default) { (action: UIAlertAction!) -> Void in
}
alert.addAction(OKAction)
guard let errorCode = FIRAuthErrorCode(rawValue: (error?.code)!) else { return }
switch errorCode {
case .ErrorCodeWrongPassword:
alert.addAction(resetPasswordAction)
case .ErrorCodeNetworkError:
print("Network error")
default:
print("Other error\n")
break
}
self.presentViewController(alert, animated: true, completion: nil)
} else { // User Logged in
self.performSegueWithIdentifier("MySegue", sender: self)
}
}
}
I only handled two errors for this example.
If you use push segue, you need to have navigation controller, and your root segue should lead to the login view controller, then another segue to the next view controller. This last segue must have an identifier (in this case it's MySegue)
Edit:
Since it seems that your problem is not with Firebase, but with setting up the storyboard. Here is an example:
Set up one UINavigationController two UIViewControllers
Control Drag between the UINavigationController to the middle UIViewControllers and choose root view controller from the popup menu
Control Drag between the UIViewController to the last UIViewControllers and choose show
select the segue added in the previous step and change its identifier (in the attributes inspector) to MySegue.
5.Choose the Middle UIViewControllers and change the class name (in the identity inspector) to your login view controller class.
Here is the full setup:
control drag menu (step 2):
Segue attributes inspector (step 4):
I found this answer mentioned here to be super elegant.
https://fluffy.es/how-to-transition-from-login-screen-to-tab-bar-controller/
it works with tab bars, and nav bars. you create a function in the scene delegate, that switches the root view controller. you access the scene delgates functions and windows with (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?

How to show one UIAlertController after the other in Swift

I want to show user a message once.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let defaultsDatafirstTrue = NSUserDefaults.standardUserDefaults()
if let _ = defaultsDatafirstTrue.stringForKey("firstTrue") {
} else {
let alertController = UIAlertController(title: "You can add road markers just do long press on the Map", message: "", preferredStyle: .Alert)
let OKAction = UIAlertAction(title: "OK", style: .Default) { (action:UIAlertAction) in
}
alertController.addAction(OKAction)
self.presentViewController(alertController, animated: true, completion:nil)
defaultsDatafirstTrue.setObject("true", forKey: "firstTrue")
}
}
But I have error Warning: Attempt to present <UIAlertController: 0x7c2a8000> on <****: 0x7d193800> whose view is not in the window hierarchy! Because at the first run the iOS app displays a warning to the user that will use the location determination.
How can I see my message after the system message?
Run the code from viewDidAppear: not from viewWillAppear:.
The problem with viewWillAppear: is that it is called before the view is actually visible, so you cannot present another view from it yet. Also, viewWillAppear: can be actually called multiple times and then cancelled (e.g. for interactive transitions).

How to unwind segue with alert view in Swift?

I have several View Controllers. I need to return to the first View Controller if the Alert View is confirmed. This is how I would do it without the unwind Segue:
#IBAction func unwindToDelete ( segue: UIStoryboardSegue ) {
let alertView = UIAlertController(title: "Delete?", message: "Are you sure you wante to delete?", preferredStyle: .ActionSheet)
let deleteAction = UIAlertAction (title: "Delete", style: .Destructive ) { alertAction in
self.deleteChoice = true
}
let cancelAction = UIAlertAction (title: "Cancel", style: .Cancel ) { alertAction in
}
alertView.addAction(deleteAction)
alertView.addAction(cancelAction)
self.presentViewController(alertView, animated: true, completion: nil)
}
But if I do that, in this code it crashes because of the last line of code.
This is the error:
2015-04-30 14:59:45.605 PhotosCollection[4624:182995]
popToViewController:transition: called on <UINavigationController 0x7a67aeb0>
while an existing transition or presentation is occurring; the navigation
stack will not be updated.
How can I complete the Alert View while being able to unwind segue.
Thank you
You are putting up the alert after the unwind has happened. You want to be able to not perform the unwind at all if the user chooses to cancel the delete. I would suggest the following:
Instead of wiring the unwind segue to your delete button, instead connect it to the view controller icon at the top of the view controller so that you can call the unwind programmatically. This answer shows you how to do that:
Setting up the unwind segue.
Give the unwind segue an identifier such as "doUnwind".
In the #IBAction for your delete button, put up the alert asking the user if they really want to delete.
In the handler for the delete button, call the unwind segue programmatically.
#IBAction func deleteButton (button: UIButton) {
let alertView = UIAlertController(title: "Delete?", message: "Are you sure you wante to delete?", preferredStyle: .ActionSheet)
let deleteAction = UIAlertAction (title: "Delete", style: .Destructive ) { alertAction in
self.performSegueWithIdentifier("doUnwind", sender: self)
}
let cancelAction = UIAlertAction (title: "Cancel", style: .Cancel ) { alertAction in
}
alertView.addAction(deleteAction)
alertView.addAction(cancelAction)
self.presentViewController(alertView, animated: true, completion: nil)
}

Creating a pop up dialog alert

I'm trying to create a popup uialert sort of to create a confirmation box. I have a button in ViewControllerTwo and when pressed navigates back to ViewControllerOne, however I want to create a popup message that asks to confirm (Yes or No) if I really want to navigate to ViewControllerOne. If yes it goes backs to ViewOne, if no it stays on the ViewTwo. How do I do this?
#IBAction func showAlertTapped(sender: AnyObject) {
//Create the AlertController
let myAlertController: UIAlertController = UIAlertController(title: "Hey..!", message: "Are You sure to Do some stuff??", preferredStyle: .Alert)
//Create and add the Cancel action
let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .Cancel) { action -> Void in
//Do some stuff
}
myAlertController.addAction(cancelAction)
//Create and an option action
let nextAction: UIAlertAction = UIAlertAction(title: "Next", style: .Default) { action -> Void in
let mainStoryboard = UIStoryboard(name: "Storyboard", bundle: NSBundle.mainBundle())
let vc : UIViewController = mainStoryboard.instantiateViewControllerWithIdentifier("vcMainLogin") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
myAlertController.addAction(nextAction)
//Present the AlertController
self.presentViewController(myAlertController, animated: true, completion: nil)
}