Reputation: 659
I am currently working on a IOS App using Swift 3. I am working on the login system. Verification of logging in works fine. The logic is that, if login succeeds, it goes to the next Screen. However, if user does not exist, it should display an error message with UIAlert. But when I try to display the UIAlert, i get an error that says "Assertion failure in -[UIKeyboardTaskQueue waitUntilAllTasksAreFinished]"
//Getting data from database
func getData() -> Void {
let url: String = "http://localhost/fridge_app/login.php" //this will be changed to the path where service.php lives
//created NSURL
let requestURL = NSURL(string: url)
//creating NSMutableURLRequest
var request = URLRequest(url: requestURL! as URL)
//setting the method to post
request.httpMethod = "POST"
//Getting values from textfield
let usernameVal = username.text
let passwordVal = password.text
//creating the post parameter by concatenating the keys and values from text field
let postString = "username=\(usernameVal!)&password=\(passwordVal!)";
print(postString)
request.httpBody = postString.data(using: String.Encoding.utf8)
//creating a task to send the post request
let task = URLSession.shared.dataTask(with: request as URLRequest){
data, response, error in
//exiting if there is some error
if error != nil{
print("error is \(error)")
return;
}
// Print out response string
var responseString: NSString?;
responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
if(responseString == "invalid"){
self.isValid = false;
print(self.isValid)
}
if self.checkLogin(data: responseString!) == true {
self.performSegue(withIdentifier: "profileViewController", sender: self)
}
else{
print("Hello")
// It prints hello fine, but when it tries to run the showAlert function it fails
self.showAlert()
}
//print("responseString = \(self.responseString)")
}
//executing the task
task.resume()
}
This is the alert function
/*
* Show UIAlert Message
*/
func showAlert() -> Void{
let alert = UIAlertController(title: "User Does Not Exist",
message: "",
preferredStyle: UIAlertControllerStyle.alert)
let loginFail = UIAlertAction(title: "Close", style: .default, handler: nil);
alert.addAction(loginFail);
present(alert, animated: true)
}
This is method is called when user clicks login.
Upvotes: 0
Views: 324
Reputation: 131418
Unless you take special steps, the completion handlers for the tasks you submit to NSURLSession get run on a background thread. That means that any UI calls you do must be sent to the main thread or they don't work correctly (And may crash your app.)
The code in your completion handler is doing more UI work than just invoking an alert. You're also invoking a segue. If your completion handler doesn't do time-consuming work you might want to wrap the whole thing in a GCD call to the main thread:
DispatchQueue.main.async() {
//Put the entire body of your completion handler in here
}
Otherwise, you'll need to individually wrap each UI call in a call to the main queue like above.
Looking at your specific completion handler, you have one if/then/else block that does UIKit calls:
if self.checkLogin(data: responseString!) {
self.performSegue(withIdentifier: "profileViewController",
sender: self)
} else {
print("Hello")
self.showAlert()
}
So just wrap that part in a call to the main queue:
DispatchQueue.main.async() {
if self.checkLogin(data: responseString!) {
self.performSegue(withIdentifier: "profileViewController",
sender: self)
} else {
print("Hello")
self.showAlert()
}
}
Upvotes: 3