Reputation: 39
I'm trying to create an app and I want to show an alert when there is a login error or if the user forget to enter a username and/or password. However, I always get this warning:
Warning: Attempt to present on whose view is not in the window hierarchy!
I have tried the other solutions I found here but I still can't fix it. Here's my code:
func createAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
self.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
@IBAction func signInPressed(_ sender: Any) {
if usernameTextField.text == "" || passwordTextField.text == "" {
createAlert(title: "Error in form", message: "Please enter an email and password.")
} else {
var activityIndicator = UIActivityIndicatorView()
activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
activityIndicator.center = self.view.center
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.shared.beginIgnoringInteractionEvents()
PFUser.logInWithUsername(inBackground: usernameTextField.text!, password: passwordTextField.text!, block: { (user, error) in
activityIndicator.stopAnimating()
UIApplication.shared.endIgnoringInteractionEvents()
if error != nil {
var displayErrorMessage = "Please try again later."
let error = error as NSError?
if let errorMessage = error?.userInfo["error"] as? String {
displayErrorMessage = errorMessage
}
self.createAlert(title: "Sign in error", message: displayErrorMessage)
} else {
print("Logged in")
self.performSegue(withIdentifier: "toSignIn", sender: self)
}
})
}
}
UPDATE: Here's the whole view controller
class ViewController: UIViewController {
@IBOutlet var usernameTextField: UITextField!
@IBOutlet var passwordTextField: UITextField!
func createAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
self.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
@IBAction func signInPressed(_ sender: Any) {
if usernameTextField.text == "" || passwordTextField.text == "" {
createAlert(title: "Error in form", message: "Please enter an email and password.")
} else {
var activityIndicator = UIActivityIndicatorView()
activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
activityIndicator.center = self.view.center
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.shared.beginIgnoringInteractionEvents()
PFUser.logInWithUsername(inBackground: usernameTextField.text!, password: passwordTextField.text!, block: { (user, error) in
activityIndicator.stopAnimating()
UIApplication.shared.endIgnoringInteractionEvents()
if error != nil {
var displayErrorMessage = "Please try again later."
let error = error as NSError?
if let errorMessage = error?.userInfo["error"] as? String {
displayErrorMessage = errorMessage
}
self.createAlert(title: "Sign in error", message: displayErrorMessage)
} else {
print("Logged in")
self.performSegue(withIdentifier: "toSignIn", sender: self)
}
})
}
}
override func viewDidAppear(_ animated: Bool) {
if PFUser.current() != nil {
performSegue(withIdentifier: "toSignIn", sender: self)
}
self.tabBarController?.tabBar.isHidden = true
}
override func viewDidLoad() {
super.viewDidLoad()
}
Upvotes: 1
Views: 4687
Reputation: 2024
Whenever We are trying to present UIAlertController inside any closure, We should call it on the main thread like:
DispatchQueue.main.async { [weak self] in
self?.createAlert(title: "Sign in error", message: displayErrorMessage)
}
Upvotes: 2
Reputation: 176
First create UIAlertController such an attribute.
var alertController: UIAlertController?
And you must add this in the viewDidLoad() like this:
override func viewDidLoad() {
super.viewDidLoad()
self.alertController = UIAlertController(title: "Alert", message: "Not images yet", preferredStyle: .alert)
self.alertController?.addAction(UIAlertAction(title: "Close", style: .default))
view.addSubview((alertController?.view)!)
}
So when you press signInButton and login is incorrect you must invoke.
@IBAction func signInPressed(_ sender: Any) {
if usernameTextField.text == "" || passwordTextField.text == "" {
createAlert(title: "Error in form", message: "Please enter an email and password.")
} else {
var activityIndicator = UIActivityIndicatorView()
activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
activityIndicator.center = self.view.center
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.shared.beginIgnoringInteractionEvents()
PFUser.logInWithUsername(inBackground: usernameTextField.text!, password: passwordTextField.text!, block: { (user, error) in
activityIndicator.stopAnimating()
UIApplication.shared.endIgnoringInteractionEvents()
if error != nil {
self.presentedViewController?.present(self.alertController!, animated: true, completion: nil)
}
}
Upvotes: 2
Reputation: 1222
Try this code for Swift 3
func displayMyAlertMessageError(userMessage:String, titleHead: String)
//define displyMyAlertMessage.
{
let MyAlert = UIAlertController(title: titleHead, message: userMessage, preferredStyle:UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title: "Okay", style: UIAlertActionStyle.default, handler: nil);MyAlert.addAction(okAction);
self.present(MyAlert,animated:true,completion:nil);
}
@IBAction func signInPressed(_ sender: Any) {
if (usernameTextField.text?.isEmpty) || (passwordTextField.text?.isEmpty)
{
createAlert(title: "Error in form", message: "Please enter an email and password.")
}
else
{
//Your code here
}
Upvotes: 0
Reputation: 401
Change your createAlert method to this,
func createAlert(title: String, message: String, controller: UIViewController) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
self.dismiss(animated: true, completion: nil)
}))
controller.present(alert, animated: true, completion: nil)
}
And then create alerts like this,
self.createAlert(title: "Sign in error", message: "Please try again later.", controller: self)
This might solve your problem.
Upvotes: -1