Reputation: 57
I am using my SignUpViewController to create an account, and when a user signs up for an account with a password that does NOT fit the password specifications, the program should throw an alert. For some reason instead, I keep getting:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIKeyboardTaskQueue waitUntilAllTasksAreFinished] may only be called from the main thread.'
How can I get back onto the main thread so that the program will just throw an alert?
Here is the code for that view controller:
@IBAction func signupPressed(_ sender: Any) {
// Get a reference to the user pool
let userPool = AppDelegate.defaultUserPool()
// Collect all of the attributes that should be included in the signup call
let emailAttribute = AWSCognitoIdentityUserAttributeType(name: "email", value: self.email.text!)
let firstNameAttribute = AWSCognitoIdentityUserAttributeType(name: "given_name", value: self.firstName.text!)
let lastNameAttribute = AWSCognitoIdentityUserAttributeType(name: "family_name", value: self.lastName.text!)
let birthdayAttribute = AWSCognitoIdentityUserAttributeType(name: "birthdate", value: self.birthday.text!)
// Actually make the signup call passing in those attributes
userPool.signUp(UUID().uuidString, password: self.password.text!, userAttributes: [emailAttribute, firstNameAttribute, lastNameAttribute, birthdayAttribute], validationData: nil)
.continueWith { (response) -> Any? in
if response.error != nil {
// Error in the signup process
let alert = UIAlertController(title: "Error", message: response.error?.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler:nil))
self.present(alert, animated: true, completion: nil)
} else {
self.user = response.result!.user
// Does user need verification?
if (response.result?.userConfirmed?.intValue != AWSCognitoIdentityUserStatus.confirmed.rawValue) {
// User needs confirmation, so we need to proceed to the verify view controller
DispatchQueue.main.async {
self.performSegue(withIdentifier: "VerifySegue", sender: self)
}
} else {
// User signed up but does not need verification
DispatchQueue.main.async {
self.presentingViewController?.dismiss(animated: true, completion: nil)
}
}
}
return nil
}
}
Upvotes: 1
Views: 2426
Reputation: 2666
In your closure, where if error is not nil, can you update the code like following and try again:
if response.error != nil {
// Error in the signup process
DispatchQueue.main.async {
let alert = UIAlertController(title: "Error", message: response.error?.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler:nil))
self.present(alert, animated: true, completion: nil)
}
}
Upvotes: 2
Reputation: 12972
Just write
self.present(alert, animated: true, completion: nil)
inside a Dispatch.main.async as you already did for the other segues
DispatchQueue.main.async {
self.present(alert, animated: true, completion: nil)
}
Upvotes: 2
Reputation: 9642
Along with DispatchQueue.main.async
, we can add [weak self]
check to avoid retain cycle, like
DispatchQueue.main.async { [weak self] in
self?.present(alert, animated: true, completion: nil)
}
Upvotes: 0
Reputation: 4453
you are already marshalling presenting the view controller and performing segue with DispatchQueue.main.async
. You should also do this to display the UIAlertController
. You might as well just marshal the entire method body to the main thread.
Upvotes: 0
Reputation: 100503
This also a main thread work
DispatchQueue.main.async {
let alert = UIAlertController(title: "Error", message: response.error?.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler:nil))
self.present(alert, animated: true, completion: nil)
}
Btw you can have only 1 DispatchQueue.main.async
to surround the response , if all things need to be done in main
Upvotes: 4