Warning: Attempt to present <UIAlertController> whose view is not in the window hierarchy - uialertview

I am trying to create and display an UIalert for my app. The problem with this alert is that I am trying to make and display an alert by writing the code in a class that is outside of the view controller. (Doing it in the class outside the view controller is important because of the other statements I have in the class UserApi pertaining to the profile image for which my alert is intended to be for.) Any idea on how to do this so I don't get the error
"Warning: Attempt to present <UIAlertController.....> : whose view is not in the window hierarchy!"?
I have already tried using UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true) instead of present(alertController, animated: true). I get the same error.
class UserApi : UIAlertController {
func signUp()....
//detect if user hasn't added a profile image and send an alert indicating the user must add a profile image
guard let imageSelected = image else {
let alertController = UIAlertController(title: "Profile Image Required",
message: "Please add a profile image to proceed." , preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default)
alertController.addAction(OKAction)
present(alertController, animated: true)
}
......

In Guard let statement, return statement is required, Please replace the following code and retry. It is working fine.
guard let imageSelected = image else {
let alertController = UIAlertController(title: "Profile Image Required",
message: "Please add a profile image to proceed." , preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default)
alertController.addAction(OKAction)
present(alertController, animated: true)
return
}

pass controller with signup function
like
func signUp(controller:UIViewController){
let alertController = UIAlertController(title: "Profile Image Required",
message: "Please add a profile image to proceed." , preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default)
alertController.addAction(OKAction)
controller.present(alertController, animated: true)
}

Related

Change UILabel Text via UIAlertAction

I want to have an alert action change the text of a UILabel in my View. Code below:
#IBAction func statusChange(_ sender: UIButton){
let playalert = UIAlertController(title: "OPERATION: \(sender.accessibilityIdentifier!) NOT POSSIBLE", message: "Convert op to PLAY mode to proceed", preferredStyle: .alert)
let recordalert = UIAlertController(title: "OPERATION: \(sender.accessibilityIdentifier!) NOT POSSIBLE", message: "Convert op to STOP mode to proceed", preferredStyle: .alert)
let statechangealert = UIAlertController(title: "OPERATION: \(sender.accessibilityIdentifier!) WILL NOW PROCEED", message: "", preferredStyle: .alert)
let stopAction = UIAlertAction(title: "Convert", style: .default, handler: { action in
self.statusDVR.text = "STOP"//"\(sender.accessibilityIdentifier!)"
})
let continueAction = UIAlertAction(title: "Continue", style: .default, handler: { action in
self.statusDVR.text = ""//"\(sender.accessibilityIdentifier!)"
})
let returnAction = UIAlertAction(title: "Return", style: .default, handler: { action -> Void in
})
playalert.addAction(stopAction)
playalert.addAction(returnAction)
recordalert.addAction(stopAction)
recordalert.addAction(returnAction)
statechangealert.addAction(continueAction)
//record was tapped, check if DVR stopped first
if (sender.tag == 5 && pwrStat == true ) {
//if not stopped send alert
if statusDVR.text != "STOP" {
self.present(recordalert, animated:true, completion: nil)
//if user tapped returned action
if statusDVR.text != "STOP" {
self.present(statechangealert, animated:true, completion: nil)
} else {
return
}
} else {
statusDVR.text = "RECORD"
}
The stopAction should convert a UILAbel called statusDVR in the view controller, but it doesn't do it.
I haven't tried implementing the other Actions yet, because I am stuck trying to figure out why my UILabel's text won't change. Thank you for any help :)
First of all, this code makes no sense:
if statusDVR.text != "STOP" {
self.present(recordalert, animated:true, completion: nil)
if statusDVR.text != "STOP" {
self.present(statechangealert, animated:true, completion: nil)
That code tries to present two alerts at the same time. That is illegal.
I think you think that when you say
self.present(recordalert, animated:true, completion: nil)
...your code magically comes to a stop while the user interacts with the alert and then proceeds after the user dismisses the alert. That’s not the case. Your code never magically stops; it just keeps right on going.
As for the actual question you asked about, the problem is simply that what you're doing is illegal:
playalert.addAction(stopAction)
playalert.addAction(returnAction)
recordalert.addAction(stopAction)
recordalert.addAction(returnAction)
No! You cannot take one UIAlertAction and somehow magically "share" it between two different UIAlertControllers. Every UIAlertController needs UIActions that belong to it alone. In other words, do not call addAction on the same UIAlertAction twice.
Just to demonstrate more simply, try running this code:
let action1 = UIAlertAction(title: "Test", style: .default) {
_ in print("test")
}
let alert1 = UIAlertController(title: "Hello", message: nil, preferredStyle: .alert)
let alert2 = UIAlertController(title: "Hello2", message: nil, preferredStyle: .alert)
alert1.addAction(action1)
alert2.addAction(action1)
self.present(alert1, animated: true, completion: nil)
The alert appears, you tap the Test button, the alert disappears — but nothing prints in the console. Now comment out the next to last line:
// alert2.addAction(action1)
... and run the code again. This time, when you tap Test, "test" appears in the console.

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.

Display an alert within an alert

I am trying to display an alert that takes user input and then pops up the text that has been given
#IBAction func forgotPassword(_ sender: Any) {
//1. Create the alert controller.
let alert = UIAlertController(title: "Email Recovery", message: "Enter your email to recover your account", preferredStyle: .alert)
//2. Add the text field. You can configure it however you need.
alert.addTextField { (textField) in
textField.text = ""
}
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
print("An email has been sent to \(String(describing: textField?.text)) for account recovery")
}))
// 4. Present the alert.
self.present(alert, animated: true, completion: nil)
}
The input works fine as well the output although instead of giving another alert, it just prints what I need in the console.
Am I missing something?
I guess you misunderstood a bit: "print" is just printing on your console, if you want to open a new alert after touching on the "ok" button, you may want to complete your code with:
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert, weak self] (_) in
let message = "An email has been sent to \(alert?.textFields?.first?.text ?? "") for account recovery"
let innerAlert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
innerAlert.addAction(UIAlertAction(title: "OK", style: .default, handler:nil))
self?.present(innerAlert, animated: true, completion: nil)
}))

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

Errors in Swift - Expected Declaration and Value of type "x" has no member "y" (Image attached)

Very new to swift and coding in general and am trying to do a basic login/register page for my application. I'm following along with an online tutorial and (as far as i'm aware) done everything exactly the same. However, I am receiving two errors when attempting to build and I can't for the life of me figure it out! Any help would be great, thanks.
Image of all code for this page including errors
First error :
let userName = someUserNameLabel.text
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setValue(userName, forKey: "userName")
userDefaults.synchronize() // don't forget this!!!!
Second error:
// Create the alert controller
var alertController = UIAlertController(title: "Alert", message: "Registration Successful", preferredStyle: .Alert)
// Create the actions
var okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) {
UIAlertAction in
NSLog("OK Pressed")
}
// Add the actions
alertController.addAction(okAction)
// Present the controller
self.presentViewController(alertController, animated: true, completion: nil)
Second error: Swift 3 update
let alertController = UIAlertController(title: "Alert", message: "Registration Successful", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default) {
print("OK Pressed")
}
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: nil)