Swift shouldSelectViewController using alertController - swift

I have what seems like a normal use case: on selecting a certain tab ('logout' in my case), I want to display an alert asking for confirmation before transitioning. This seems like it should be handled in the shouldSelectViewController function. However, the alertController is async, and I'm forced to return a boolean before it completes. It doesn't seem likely that shouldSelectViewController should wait for an async task before completing. Is there a better place for me to trigger my confirmation alert before switching views?
This is my code:
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
if (viewController is Trove.HomeViewController) {
var shouldSelect = false
let alertController = UIAlertController(title: "Logout", message: "Are you sure you want to log out?", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Logout", style: .Default) { (action) in
shouldSelect = true
}
alertController.addAction(okAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in }
alertController.addAction(cancelAction)
tabBarController.presentViewController(alertController, animated: true) { return shouldSelect}
}
return true
}
Any help is much appreciated! Thanks!

You can try setting the selecedIndex property of the UITabBarController.
Your new if statement:
if (viewController is Trove.HomeViewController) {
let alertController = UIAlertController(title: "Logout", message: "Are you sure you want to log out?", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Logout", style: .Default) { (action) in
tabBarController.selectedIndex = 0 //CHANGE ME
}
alertController.addAction(okAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in }
alertController.addAction(cancelAction)
tabBarController.presentViewController(alertController, animated: true)
return false
}

Related

Swift4 - Multiple Alerts with Text Field - Completion Handler

i am working at my startscreen (viewDidAppear). At the beginning of the app, there should be an alert with some notice message. This works fine. After you click "ok" at the notice, the next alert should pop up with a text field. In this text field you have to type in a double value. I need this double value to set up a lot of things inside the app, so I need this value outside the function to calculate with it.
E.g. The notice message describes how the app works. You click OK. Now the next alert pop up with the text field. For example it asks your height. After you type in your height and click OK the height-value is the main part of different calculations.
The problem is now, that my app works with the nil-value before I typed in the double value (e.g. height)
These are the snippets from the code.
var iNeedTheDataHere:String?
///Alerts
//Start
let startController = UIAlertController(title: "Notice", message: "notice message ", preferredStyle: .alert)
let inputController = UIAlertController(title: "Set input", message: "Please set the input", preferredStyle: .alert)
//BeforeScreenLoad
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Start Alert
startController.addAction(UIAlertAction(title: "OK", style: .default, handler:{(action:UIAlertAction!) in
self.input()
}))
self.present(startController, animated: true)
}
func input() {
inputController.addTextField()
let submitAction = UIAlertAction(title: "Submit", style: .default) { [unowned ac] _ in
let answer = inputController.textFields![0].text
iNeedTheDataHere = answer
}
inputController.addAction(submitAction)
}
When I set Breakpoints, I see that the value of the inputController is set to nil, before I typed in anything. I guess my mistake has something to do with the handler
Sorry for my English
Hope somebody can help me
let alert = UIAlertController(title: "Alert!!!", message: "Please enter your message ", preferredStyle: .alert)
alert.addTextField(configurationHandler: self.configurationTextField)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler:{ (UIAlertAction) in
self.number.text?=""
MBProgressHUD.hide(for: self.view, animated: true)
}))
alert.addAction(UIAlertAction(title: "Done", style: .default, handler:{ (UIAlertAction) in
}))
self.present(alert, animated: true, completion: {
})
I have made some changes in your code to achieve that:
class ViewController: UIViewController {
let startController = UIAlertController(title: "Notice", message: "notice message ", preferredStyle: .alert)
let inputController = UIAlertController(title: "Set input", message: "Please set the input", preferredStyle: .alert)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(_ animated: Bool) {
startController.addAction(UIAlertAction(title: "OK", style: .default, handler:{(action:UIAlertAction!) in
self.input()
}))
self.present(startController, animated: true)
}
func input() {
//Present another alert with textField
let confirmAction = UIAlertAction(title: "Submit", style: .default) { (_) in
guard let textFields = self.inputController.textFields,
textFields.count > 0 else {
// Could not find textfield
return
}
//get your textField
let answerTF = textFields[0]
let answer = answerTF.text
//Get values entered by user
print(answer)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
//add your textField here
inputController.addTextField { (textField) in
//Set a placeholde for textField
textField.placeholder = "Answer"
}
inputController.addAction(confirmAction)
inputController.addAction(cancelAction)
self.present(inputController, animated: true, completion: nil)
}
}
I have added comment to explain what I am doing.
And your result will be:
You can also check demo project here.

how to display alert controller only once when the UITextfield is tapped?

I'm trying to prevent user from manipulating with their data, so when they tap on UITextfield an alertController shall be displayed only once, after they press "yes" option, then they shall be able to change data. but instead of displaying alert controller once, it keeps displaying every time I tap on UITextfield; how I can solve this issue.
func textFieldDidBeginEditing(textField: UITextField) {
let alert = UIAlertController(title: "Warning !", message: "Are your sure you want to change your content? ", preferredStyle: .Alert)
let yes = UIAlertAction(title: "Yes", style: .Cancel) { (action) in
}
alert.addAction(yes)
let no = UIAlertAction(title: "No", style: .Default) { (action) in
}
alert.addAction(no)
presentViewController(alert, animated: true) {}
}
textField.becomeFirstResponder()
}
var alertWillShow = true
func textFieldDidBeginEditing(textField: UITextField) {
if alertWillShow {
alertWillShow = false
let alert = UIAlertController(title: "Warning !", message: "Are your sure you want to change your content? ", preferredStyle: .Alert)
let yes = UIAlertAction(title: "Yes", style: .Cancel) { (action) in
}
alert.addAction(yes)
let no = UIAlertAction(title: "No", style: .Default) { (action) in
}
alert.addAction(no)
presentViewController(alert, animated: true) {}
}
}
textField.becomeFirstResponder()
}

Open a new view controller after login alert swift 2.0

I am trying to change view controller if the login is successful but I am unsure how to do this. This is what i have tried so far. Thanks in advance!
#IBAction func signinaction(sender: AnyObject) {
let user = self.usernamefield.text!
ref.authUser(emailfield.text, password: passwordfield.text, withCompletionBlock: { error, authData in
if error != nil
{
let alert = UIAlertController(title: "Error", message: "Enter Email and Password.", preferredStyle: UIAlertControllerStyle.Alert)
let action = UIAlertAction(title: "Ok", style: .Default, handler: nil)
alert.addAction(action)
self.presentViewController(alert, animated: true, completion: nil)
print("can not sign in")
}
else
{
let storyboard = UIStoryboard(name: "Main", bundle: nil);
let viewName:NSString = "NewView"
let vc = storyboard.instantiateViewControllerWithIdentifier(viewName as String) as! HomeViewController
let uid = authData.uid
print("Success with user: \(uid)")
let alert = UIAlertController(title: "Success", message: "Welcome \(user)", preferredStyle: UIAlertControllerStyle.Alert)
let action = UIAlertAction(title: "Ok", style: .Default, handler: nil)
alert.addAction(action)
self.navigationController?.pushViewController(vc as HomeViewController, animated: true)
}
})
}
Assuming that the view controller all of this is in is contained in a navigation controller, what you have should be working fine. Note, however that you're creating an alert you never show. My guess is that you want to display the success alert and then open the new view controller, something like:
let alert = UIAlertController(title: "Success", message: "Welcome \(user)", preferredStyle: UIAlertControllerStyle.Alert)
let action = UIAlertAction(title: "Ok", style: .Default) { _ in
self.navigationController?.pushViewController(vc, animated: true)
}
alert.addAction(action)
self.presentViewController(alert, animated: true, completion: nil)
If this still isn't working, I'd make sure the current view controller is actually displayed in a navigation controller.
Looks like you just need to add the navigation code inside of the alert action. Currently you have the handler parameter set to nil
this
let action = UIAlertAction(title: "Ok", style: .Default, handler: nil)
becomes this
let alertAction = UIAlertAction(title: "Ok", style: .Default) { (action) -> Void in
self.navigationController?.pushViewController(vc as HomeViewController, animated: true)
}

Use of unresolved identifier using an alert.addAction

I'm getting an error on my alert.addAction(). Seems like my project doesn't know where to find it, am I right?
I made an alert without buttons, now I'm trying to add buttons to it.
So this is my alert window and the code to add the buttons:
func naamInModelChangedHandler ( notification:NSNotification ) {
println("De naam in de model is veranderd naar \(model.naam!)")
NSNotificationCenter.defaultCenter().removeObserver(
self,
name: "NAAM_CHANGED",
object: model)
let alert = UIAlertController(title: "Ola", message: "De naam is gewijzigd", preferredStyle: UIAlertControllerStyle.Alert)
self.presentViewController(alert, animated: true, completion: nil)
alert.addAction(okAction)
alert.addAction(cancelAction)
}
I've made a UIAlertAction with the name AlertController with some code to make the buttons.
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) { (action) -> Void in
println("Ok geklikt")
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) { (action) -> Void in
println("Cancel geklikt")
}
But it seems it doesn't know where to look for I think. What am I doing wrong here?
Do like this
func naamInModelChangedHandler ( notification:NSNotification ) {
println("De naam in de model is veranderd naar \(model.naam!)")
NSNotificationCenter.defaultCenter().removeObserver(
self,
name: "NAAM_CHANGED",
object: model)
let alert = UIAlertController(title: "Ola", message: "De naam is gewijzigd", preferredStyle: UIAlertControllerStyle.Alert)
self.presentViewController(alert, animated: true, completion: nil)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) { (action) -> Void in
println("Ok geklikt")
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) { (action) -> Void in
println("Cancel geklikt")
}
alert.addAction(okAction)
alert.addAction(cancelAction)
}

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.