I'm somewhat new to Swift and have mostly figured out how to use completion handlers with the help of this site. After a couple of days trying to get this to work, I'd appreciate more direct help.
I have a:
@IBAction func submitRegistrationButton(_ sender: Any) {
if((firstNameField.text?.trimmingCharacters(in: .whitespacesAndNewlines).characters.count) == 0){
showXAlert(title: "Oops!", message: "Please enter your first name.", viewController: self)
}else if((lastNameField.text?.trimmingCharacters(in: .whitespacesAndNewlines).characters.count) == 0){
showXAlert(title: "Oops!", message: "Please enter your last name.", viewController: self)
}else if((emailAddressField.text?.trimmingCharacters(in: .whitespacesAndNewlines).characters.count) == 0){
showXAlert(title: "Oops!", message: "Please enter your email address.", viewController: self)
}else if !isValidEmail(testStr: emailAddressField.text!){
showXAlert(title: "Oops!", message: "Please enter a valid email address.", viewController: self)
}else if((passwordField.text?.trimmingCharacters(in: .whitespacesAndNewlines).characters.count) == 0){
showXAlert(title: "Oops!", message: "Please enter a password.", viewController: self)
}else if passwordField.text != passwordConfirmationField.text{
showXAlert(title: "Oops!", message: "Your password and password confirmation do not match. Please correct.", viewController: self)
}else{
registrant.firstName = firstNameField.text!
registrant.lastName = lastNameField.text!
registrant.zipCode = zipCodeField.text!
registrant.emailAddress = emailAddressField.text!
registrant.password = passwordField.text!
storeRegistrationInfo(registrant: registrant) { (object: XUserAPIResult) in
print("submissionStatus = \(object.success)")
if object.success == 1 {
showXAlert(title: "Welcome \(self.registrant.firstName)!", message: "Your registration was submitted successfully. Log in by clicking the Login button below", viewController: self)
}else{
showXAlert(title: "Un Oh", message: "There was a problem with your registration. \(object.errorMessage)", viewController: self)
}
}
}
}
...that calls:
func storeRegistrationInfo(registrant: XRegistrantInfo, finished: @escaping (XUserAPIResult)->()) {
var apiResult = XUserAPIResult()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let newRegistrant = NSEntityDescription.insertNewObject(forEntityName: "User", into: context)
let requestURL = NSURL(string: USER_API_URL)
let request = NSMutableURLRequest(url: requestURL! as URL)
request.httpMethod = "POST"
newRegistrant.setValue(registrant.firstName, forKey: "firstName")
newRegistrant.setValue(registrant.lastName, forKey: "lastName")
newRegistrant.setValue(registrant.zipCode, forKey: "zipCode")
newRegistrant.setValue(registrant.emailAddress, forKey: "emailAddress")
newRegistrant.setValue(registrant.password, forKey: "password")
newRegistrant.setValue(registrant.personna, forKey: "personna")
do{
try context.save()
let postParameters = "tag=" + REGISTRATION_API_TAG + "&firstName=" + registrant.firstName + "&lastName=" + registrant.lastName + "&password=" + registrant.password + "&username=" + registrant.emailAddress + "&personna=" + registrant.personna + "&zipCode=" + registrant.zipCode
request.httpBody = postParameters.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest){
data, response, error in
if error != nil{
print("error is \(error)")
return
}
print("response = \(response)")
//parsing the response
do {
//converting resonse to NSDictionary
let myJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
//parse json 2
if let dictionary = myJSON as? [String: Any]{
if let apiSuccess = dictionary["success"] as? Int{
apiResult.success = apiSuccess
}
if let apiError = dictionary["error"] as? Int{
apiResult.error = apiError
if apiError != 0{
if let apiErrorMessage = dictionary["error_msg"] as? String{
apiResult.errorMessage = apiErrorMessage
}
}else{
if let apiUID = dictionary["uid"] as? String{
apiResult.uniqueID = apiUID
}
if let nestedDictionary = dictionary["user"] as? [String: Any]{
if let apiFirstName = nestedDictionary["firstName"] as? String{
apiResult.user.firstName = apiFirstName
}
if let apiLastName = nestedDictionary["lastName"] as? String{
apiResult.user.lastName = apiLastName
}
if let apiEmail = nestedDictionary["e-mail"] as? String{
apiResult.user.emailAddress = apiEmail
}
if let apiCreatedAt = nestedDictionary["created_at"] as? String{
apiResult.user.createdAt = apiCreatedAt
}
if let apiPersonna = nestedDictionary["personna"] as? String{
apiResult.user.personna = apiPersonna
}
}
finished(apiResult)
}
}
}
} catch {
print(error)
}
}
task.resume()
finished(apiResult)
} catch {
print("There was an error saving to Core Data")
finished(apiResult)
}
}
The submitRegistrationButton() code is supposed to wait until storeRegistrationInfo() returns a XUserAPIResult struct and then display the appropriate alert based on XUserAPIResult's success property.
The problem is that the success-checking code is being executed both before storeRegistrationInfo() completes parsing the JSON; displaying the wrong alert, and then executed correctly after the JSON is parsed. The other aspects of the code (the web API call, parsing the JSON, saving the data to the web database) works.
I'm pretty sure there is something wrong with how I'm using the completion handler or calling storeRegistrationInfo() but I'm not sure exactly how to fix it.
How do I make sure that the alert code in @IBAction func submitRegistrationButton(_ sender: Any):
storeRegistrationInfo(registrant: registrant) { (object: XUserAPIResult) in
print("submissionStatus = \(object.success)")
if object.success == 1 {
showXAlert(title: "Welcome \(self.registrant.firstName)!", message: "Your registration was submitted successfully. Log in by clicking the Login button below", viewController: self)
}else{
showXAlert(title: "Un Oh", message: "There was a problem with your registration. \(object.errorMessage)", viewController: self)
}
}
...is only called after the JSON is parsed and the UserAPIResult struct is populated and passed back?
Thanks.