Elan Kainen
Elan Kainen

Reputation: 57

How to get back on Main thread in Xcode?

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

Answers (5)

emrepun
emrepun

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

superpuccio
superpuccio

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

Bappaditya
Bappaditya

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

yano
yano

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

Shehata Gamal
Shehata Gamal

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

Related Questions