Action sheet does not work in iPhone simulator - iphone

I am trying to implement the Action sheet in Swift. Below is the code to implement it. When i execute the code, Xcode does not show any errors and the action sheet does not appear in the simulator. Any help in resolving the issue is much appreciated.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
func showActionSheet(sender: AnyObject) {
let actionSheetController: UIAlertController = UIAlertController(title: "Action Sheet", message: "Choose an option!", preferredStyle: .actionSheet)
//Create and add the Cancel action
let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in
//Just dismiss the action sheet
}
actionSheetController.addAction(cancelAction)
self.present(actionSheetController, animated: true, completion: nil)

The way your code is provided, it looks as if you added a method/function inside viewWillAppear. If that is not a typing mistake and you did indeed set your code up like that, modifying your code to look like this will get it to work:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let actionSheetController: UIAlertController = UIAlertController(title: "Action Sheet", message: "Choose an option!", preferredStyle: .actionSheet)
//Create and add the Cancel action
let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in
//Just dismiss the action sheet
}
actionSheetController.addAction(cancelAction)
self.present(actionSheetController, animated: true, completion: nil)
}
Basically, do not have a method inside viewWillAppear but also move your action sheet display code to viewDidAppear instead of viewWillAppear

Related

UIAlertController is complete and presented but does not appear during viewDidLoad

I have this alert controller setup to appear as soon as the view controller is loaded. However, it does not appear.
I believe I have all the facets covered - title, message, alert style, action button and present... but still does not appear.
Unsure what I'm missing.
let array = quoteBank()
print(array.sarcasticQuotes[0].quote)
let title = "Message"
let message = array.sarcasticQuotes[0].quote
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(.init(title: "OK", style: .default, handler: nil))
present(alert, animated: true, completion: nil)
Attempting to show an alert in viewDidLoad is too soon. The view controller isn't displayed yet. Use viewDidAppear.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Use this if statement to only show the alert once
if self.isBeingPresented || self.isMovingToParentViewController {
// show your alert here
}
}
You need to perform that on the main thread:
DispatchQueue.main.async {
present(alert, animated: true, completion: nil)
}
The reason behind that is that the view controller's hierarchy will be set after viewDidLoad is finished. So by doing this, you're scheduling the presentation of the alert on the main thread to the time the main thread is finished from executing viewDidLoad.

How To Make an Alert Only Appear Once

I'm trying to figure out is how to create a pop up window that only appears once when you start the app and then won't appear again unless you close the app and reboot it. However, if you view the code below, you will realize that the alert will pop up every time the ViewController appears. For example, if you go to the settings tab and then return to the main ViewController, then the alert will pop up.
override func viewDidAppear(animated: Bool) {
let alertController = UIAlertController(title: "Disclaimer", message: "WARNING: Please ride carefully!", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "Accept", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
}
Just create a global variable that is a Bool. If the app is opened it starts at false. Then once the disclaimer is seen it sets the variable to true. Then present the View Controller based on the value of the variable.
var disclaimerHasBeenDisplayed = false
class ViewController {
override func viewDidAppear(animated: Bool) {
if disclaimerHasBeenDisplayed == false {
disclaimerHasBeenDisplayed = true
let alertController = UIAlertController(title: "Disclaimer", message: "WARNING: Wakeboarding is fun, however it can be highly dangerous.
Wake Dice is not liable for any injuries obtained while wakeboarding. Please ride carefully!", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "Accept", style: UIAlertActionStyle.Default,handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
}
}
}

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

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

How do we create and dismiss an UIAlertController without user input? (Swift)

I've been looking up a lot of tutorials on UIAlertController. Thus far, the way I found was to activate a UIAlertController by linking it to a button or label and then call a IBAction.
I tried to replicate the code to automatically pop an alert when user enters the app (I wanted to ask the user if they want to go through the tutorial). However, I keep getting the error:
Warning: Attempt to present UIAlertController on MainViewController whose view is not in the window hierarchy!
Then I tried to add the UIAlertController to the MainViewController via addChildViewController and addSubview. However, I get the error:
Application tried to present modally an active controller
I figured that I cannot use the presentViewController function and commented it out.
The UIAlertController is displayed BUT when I tried to click on the cancel or the never button, this error occurs.
Trying to dismiss UIAlertController with unknown presenter.
I am really stumped. Can someone share what I am doing wrong? Thank you so much. Here is the code.
func displayTutorial() {
alertController = UIAlertController(title: NSLocalizedString("tutorialAlert", comment: ""), message: NSLocalizedString("tutorialMsg", comment: ""), preferredStyle: .ActionSheet)
self.addChildViewController(alertController)
self.view.addSubview(alertController.view)
alertController.didMoveToParentViewController(self)
alertController.view.frame.origin.x = self.view.frame.midX
alertController.view.frame.origin.y = self.view.frame.midY
//alertController.popoverPresentationController?.sourceView = self.view*/
let OkAction = UIAlertAction(title: NSLocalizedString("yesh", comment: ""), style: .Destructive) { (action) in
}
alertController.addAction(OkAction)
let cancelAction = UIAlertAction(title: NSLocalizedString("notNow", comment: ""), style: .Destructive) { (action) in
//println(action)
self.tutorial = 1
self.presentedViewController?.dismissViewControllerAnimated(true, completion: nil)
}
alertController.addAction(cancelAction)
let neverAction = UIAlertAction(title: NSLocalizedString("never", comment: ""), style: .Cancel) { (action) in
self.tutorial = 1
}
alertController.addAction(neverAction)
//self.presentViewController(alertController, animated: false) {}
}
I found the solution. Apparently, I cannot call the UIAlertController from the func viewDidLoad. I must call the function from viewDidAppear. So my code now is
override func viewDidAppear(animated: Bool) {
if tutorial == 0 {
displayTutorial(self.view)
}
}
func displayTutorial(sender:AnyObject) {
let alertController = UIAlertController(title: NSLocalizedString("tutorialAlert", comment: ""), message: NSLocalizedString("tutorialMsg", comment: ""), preferredStyle: .ActionSheet)
let OkAction = UIAlertAction(title: NSLocalizedString("yesh", comment: ""), style: .Destructive) { (action) in
}
alertController.addAction(OkAction)
let cancelAction = UIAlertAction(title: NSLocalizedString("notNow", comment: ""), style: .Default) { (action) in
//println(action)
self.tutorial = 1
self.presentedViewController?.dismissViewControllerAnimated(true, completion: nil)
}
alertController.addAction(cancelAction)
let neverAction = UIAlertAction(title: NSLocalizedString("never", comment: ""), style: .Cancel) { (action) in
self.tutorial = 1
}
alertController.addAction(neverAction)
self.presentViewController(alertController, animated: true, completion: nil)
if let pop = alertController.popoverPresentationController {
let v = sender as UIView
pop.sourceView = view
pop.sourceRect = v.bounds
}
}
Thanks to this posting: Warning: Attempt to present * on * whose view is not in the window hierarchy - swift
Below UIAlertController with extension would help you show alert with dynamic number of buttons with completion handler for selected index
extension UIViewController {
func displayAlertWith(message:String) {
displayAlertWith(message: message, buttons: ["Dismiss"]) { (index) in
}
}
func displayAlertWith(message:String, buttons:[String], completion:((_ index:Int) -> Void)!) -> Void {
displayAlertWithTitleFromVC(vc: self, title: Bundle.main.infoDictionary!["CFBundleDisplayName"] as! String, andMessage: message, buttons: buttons, completion: completion)
}
func displayAlertWithTitleFromVC(vc:UIViewController, title:String, andMessage message:String, buttons:[String], completion:((_ index:Int) -> Void)!) -> Void {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
for index in 0..<buttons.count {
let action = UIAlertAction(title: buttons[index], style: .default, handler: {
(alert: UIAlertAction!) in
if(completion != nil){
completion(index)
}
})
alertController.addAction(action)
}
DispatchQueue.main.async {
vc.present(alertController, animated: true, completion: nil)
}
}
}
If you need to auto dismiss the alert you can call dismiss on presented view controller after some delay.
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
vc.dismiss(animated: true, completion: nil)
}
Hope this might help you.