My view is being dismissed through the previous button on the navigation bar. I think the correct term for that is that the view is being popped off the view stack. Now before actually dismissing the view I want to display a UIAlert asking the user to setup his/her address.
I've tried this but the UIAlert is not being show:
override func viewWillDisappear(animated: Bool) {
if let currentUser = ApiManager.sharedInstance.currentUser {
if !currentUser.hasAddress {
let alert = UIAlertController(title: "Missing address", message: "We see you're stilling missing an address, would you like set it now?", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "yes".localized, style: .Default, handler: { (alertAction) in
let newViewController = LocationViewController()
newViewController.delegate = self
self.navigationController?.pushViewController(newViewController, animated: true)
}))
alert.addAction(UIAlertAction(title: "no".localized, style: .Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
}
In my console the following gets printed:
2016-10-28 16:58:47.380 gaifong[17096:14515422] Warning: Attempt to present <UIAlertController: 0x7fd7037e4cb0> on <gaifong.ProfileViewController: 0x7fd7048cc000> whose view is not in the window hierarchy!
You should add leftBarButtonItem on navigationItem and make an action to leftBarButtonItem where you can handle this.
in viewDidLoad
self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: image, style: UIBarButtonItemStyle.Plain, target: self, action: #selector(self.goBack))
// Then handle the button selection
func goBack() {
if let currentUser = ApiManager.sharedInstance.currentUser {
if !currentUser.hasAddress {
let alert = UIAlertController(title: "Missing address", message: "We see you're stilling missing an address, would you like set it now?", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "yes".localized, style: .Default, handler: { (alertAction) in
// here you can pop to main controller
self.navigationController?.popViewControllerAnimated(true)
}))
alert.addAction(UIAlertAction(title: "no".localized, style: .Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
}
Related
I have a UIAlertController in which the options are populated from an array and are presented to the user. The user then selects an option from the alert. After this, I have a separate alert that provides the user with a confirmation message that has an okay button.
myAlert.addAction(UIAlertAction.init(title: item, style: .Default, handler: {
(UIAlertAction) in
self.chosenBusiness.append(businessNameData[item]!)
}))
self.presentViewController(myAlert, animated: true, completion: nil)
The code above gathers the data from the array and pushes it into actions in myAlert. The code above is inside of a for loop.
After this I use a function to retrieve the topmost view controller, and then push the next alert.
let top = topMostController()
let alertController = UIAlertController(title: "Location pinned", message: "You've successfully pinned this location, good work!", preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) {
(result : UIAlertAction) -> Void in
print("OK")
}
alertController.addAction(okAction)
self.presentViewController(myAlert, animated: true, completion: nil)
top.presentViewController(alertController, animated: true, completion: {
_ in
})
The error I receive is:
Attempting to load the view of a view controller while it is
deallocating and is not allowed and may result in undefined behavior.
UIAlertController: 0x1535b1cd0.
Can someone help me with this?
I think this is what you are looking for. The second must be called with the dismissal action of the first. Also, anytime you work with UI, It is safer to use dispatch_async(dispatch_get_main_queue()) {
\\code }
than not if you are not positive you are currently on the main queue.
let firstAlertController = UIAlertController(title: "First", message: "This is the first message.", preferredStyle: UIAlertControllerStyle.Alert)
let secondAlertController = UIAlertController(title: "Second", message: "This is the second message.", preferredStyle: UIAlertControllerStyle.Alert)
let secondDismissAction = UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, completion: nil)
secondAlertController.addAction(secondDismissAction)
let firstDismissAction = UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default) {
UIAlertAction in
dispatch_async(dispatch_get_main_queue()) {
self.presentViewController(secondAlertController, animated: true, handler: nil)
}
}
firstAlertController.addAction(firstDismissAction)
self.presentViewController(firstAlertController, animated: true, completion: nil)
I'm quite new to Swift (and coding in general) and to this website.
I'm having a little bit of an issue now. In my app, I have an alert when a timer reaches 0. In that alert, there are 2 buttons. One says "Share" and the other says "Continue". I want to make it such that when a user taps "Continue", the next Storyboard will be shown to them. As of now, whatever button I press will dismiss the alert, but stay on the same Storyboard. (It also prints to the console which button I pressed, but of course that's just for me to see).
How do I go about doing this? Here is my code, in case anyone wants to know.
let alert = UIAlertController(title: "Time's Up!", message: "What would you like to do now?", preferredStyle: .Alert)
let firstAction = UIAlertAction(title: "Continue", style: .Default) { (alert: UIAlertAction!) -> Void in
NSLog("You pressed button one")
}
let secondAction = UIAlertAction(title: "Share", style: .Default) { (alert: UIAlertAction!) -> Void in
NSLog("You pressed button two")
}
alert.addAction(firstAction)
alert.addAction(secondAction)
presentViewController(alert, animated: true, completion:nil)
Try with this:
// Create the alert controller
var alertController = UIAlertController(title: "Title", message: "Message", preferredStyle: .Alert)
// Create the actions
var okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) {
UIAlertAction in
NSLog("OK Pressed")
let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("someViewController") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
var cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
//do whatever you want here
}
// Add the actions
alertController.addAction(okAction)
alertController.addAction(cancelAction)
// Present the controller
self.presentViewController(alertController, animated: true, completion: nil)
If you haven't already set your ViewControllerIdentifier:
You need to set the Identifier value that you can find on the right column
Here is the code that might help you. When you create a AlertController with actions, you can provide the actions and style of the button when you define them. In code below action is in the closure (Block) and style is defined as .Default or .Cancel
let alert = UIAlertController(title: "Time's Up!", message: "What would you like to do now?", preferredStyle: .Alert)
let firstAction = UIAlertAction(title: "Continue", style: .Default) { (alert: UIAlertAction!) -> Void in
// Action when you press button goes here
print("Here you show next storyboard item.")
// Code to push new ViewController. For example :
self.navigationController?.pushViewController(newVCInstance, animated: true)
}
let secondAction = UIAlertAction(title: "Share", style: .Default) { (alert: UIAlertAction!) -> Void in
print("Here you share things.")
// Code to share things.
}
let thirdAction = UIAlertAction(title: "Cancel", style: . Cancel) { (alert: UIAlertAction!) -> Void in
print("Just dismissing the Alert Controller.")
}
alert.addAction(firstAction)
alert.addAction(secondAction)
alert.addAction(thirdAction)
presentViewController(alert, animated: true, completion:nil)
I am trying to popViewController to the previous View Controller in the navigation stack after an alertView. As of now, my program will not run the popViewController method, since the alertView is in the way, and brings up the error:
UINavigationController 0x17670900 while an existing transition or presentation is occurring; the navigation stack will not be updated.
How do I go about running the popViewController method after the user clicks OK from the alertView? Do I have to set a delegate which detects when the used clicks OK?
Here is my code:
//alertView after Picture saved
let alertView = UIAlertController(title: "Success!", message: "Record Saved to Database", preferredStyle: .Alert)
alertView.addAction(UIAlertAction(title: "Ok", style: .Default, handler: nil))
self.presentViewController(alertView, animated: true, completion: nil)
//go to previous controller using popViewController, doesnt work, brings up error message
if let navController = self.navigationController {
navController.popViewControllerAnimated(true)
}
You need to pop the view controller when user presses the Ok button from AlertView.
let alertView = UIAlertController(title: "Success!", message: "Record Saved to Database", preferredStyle: .Alert)
let OKAction = UIAlertAction(title: "Ok", style: .Default) { (action) in
// pop here
if let navController = self.navigationController {
navController.popViewControllerAnimated(true)
}
}
alertView.addAction(OKAction)
self.present(alertView, animated: true, completion: nil)
You can put the "popViewControllerAction" inside an alert action like this.
func alertMethod() {
var okAlertController = UIAlertController(title: NSLocalizedString("Your title", comment: ""), message: "Your message", preferredStyle:
UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title: NSLocalizedString("Ok", comment: ""), style: UIAlertActionStyle.Default) { (UIAlertAction) -> Void in
// your action - navController.popViewControllerAnimated(true)
}
let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: UIAlertActionStyle.Default) { (UIAlertAction) -> Void in
// your action
}
}
saveAlertController.addAction(okAction)
saveAlertController.addAction(cancelAction)
self.presentViewController(okAlertController, animated: true, completion: nil)
}
That should work, in that case the method gets called after the user presses a button...
The UIAlertViewController shows all my text but on clicking doesn't switch to the other View. Here's the code:
let alertController = UIAlertController(title: "Risposta Esatta", message:"", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "Avanti", style:UIAlertActionStyle.Default,handler: {(UIAlertAction) in
let secondViewController:SecondViewController = SecondViewController()
self.presentViewController(secondViewController, animated: true, completion: nil)
}))
This just worked for me:
#IBAction func choiceBtn(sender: UIButton) {
let alertController = UIAlertController(title: "Hello!", message: "This is Alert sample.", preferredStyle: .Alert)
let otherAction = UIAlertAction(title: "OK", style: .Default) {
action in println("pushed OK!")
}
let cancelAction = UIAlertAction(title: "CANCEL", style: .Cancel) {
action in self.performSegueWithIdentifier("VC2", sender: self)
}
alertController.addAction(otherAction)
alertController.addAction(cancelAction)
presentViewController(alertController, animated: true, completion: nil)
}
I created a modal presented segue from VC1 to VC2 and also named the identifier VC2. This code I adapted from the GitHub UIAlertController example here:
https://github.com/eversense/Swift-UIAlertController-Example
There was no segue to another ViewController, so I added that to show you.
I have a view controller which contains a sub-view. And inside the sub-view class, I may need to pop out an alert when some condition is satisfied.
class GameViewController: UIViewController {
#IBOutlet var gameBoardUIView: GameBoardUIView
...
}
class GameBoardUIView: UIView {
...
func move() {
if !gameBoard.checkNextMoveExist() {
var alert = UIAlertController(title: "Game Over", message: nil, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Take Me Back", style: UIAlertActionStyle.Cancel, handler: {(action: UIAlertAction!) in
println("Taking user back to the game without restarting")
}))
alert.addAction(UIAlertAction(title: "New Game", style: UIAlertActionStyle.Destructive, handler: {(action: UIAlertAction!) in
println("Starting a new game")
self.restartGame()
}))
// This is where the question is
// self.presentViewController(alert, animated: true, completion: nil)
}
}
}
As you can see from the code, I cannot call presentViewController function to show the alert because my sub view is not a controller class. Should I somehow create a week reference to the parent controller inside the sub-view? What would be the best practice to implement such reference?
Swift 4
Just present the alert in UIApplication windows in root view controller:
let title = "Some title"
let message = "body message"
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let action = UIAlertAction(title: "Aceptar", style: .cancel, handler: nil)
alert.addAction(action)
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
there are couple of ways how you can catch a UIViewController in your UIView.
you can make any of your view controllers as a delegate to show an alert;
you can pass a view controller's reference to your view; and
in general you can always grab the rootViewController anywhere in your code.
you need to call the dismissViewControllerAnimated(_: completion:) on the same view controller when you'd like to dismiss your alert later.
thus, I'd do such a quick solution for your case:
func move() {
if !gameBoard.checkNextMoveExist() {
let rootViewController: UIViewController = UIApplication.sharedApplication().windows[0].rootViewController
var alert = UIAlertController(title: "Game Over", message: nil, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Take Me Back", style: UIAlertActionStyle.Cancel, handler: {(action: UIAlertAction!) in
rootViewController.dismissViewControllerAnimated(true, completion: nil)
println("Taking user back to the game without restarting")
}))
alert.addAction(UIAlertAction(title: "New Game", style: UIAlertActionStyle.Destructive, handler: {(action: UIAlertAction!) in
rootViewController.dismissViewControllerAnimated(true, completion: nil)
println("Starting a new game")
self.restartGame()
}))
rootViewController.presentViewController(alert, animated: true, completion: nil)
}
}