Swift 在解释响应之前,如何确保此函数已完成?

Swift 在解释响应之前,如何确保此函数已完成?,swift,asynchronous,completionhandler,Swift,Asynchronous,Completionhandler,我对Swift有些陌生,在这个网站的帮助下,我基本上已经学会了如何使用完成处理程序。经过几天的努力,我希望能得到更多的直接帮助 我有一个: @IBAction func submitRegistrationButton(_ sender: Any) { if((firstNameField.text?.trimmingCharacters(in: .whitespacesAndNewlines).characters.count) == 0){ showXAlert(t

我对Swift有些陌生,在这个网站的帮助下,我基本上已经学会了如何使用完成处理程序。经过几天的努力,我希望能得到更多的直接帮助

我有一个:

@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)
                        }

                    }
                }
}
…这就要求:

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)
    }
}
submitRegistrationButton()代码应该等待storeRegistrationInfo()返回一个XUserAppResult结构,然后根据XUserAppResult的成功属性显示相应的警报

问题是成功检查代码在storeRegistrationInfo()完成JSON解析之前执行;显示错误的警报,然后在解析JSON后正确执行。代码的其他方面(web API调用、解析JSON、将数据保存到web数据库)也可以工作

我很确定我使用完成处理程序或调用storeRegistrationInfo()的方式有问题,但我不确定确切的修复方法

如何确保@IBAction func submitRegistrationButton(u-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)
   }    
}
…仅在解析JSON并填充并传回UserAPIResult结构后调用

谢谢。

试试下面的方法

typealias CompletionHandler = (data:XRegistrantInfo,success:Bool) -> Void;


func storeRegistrationInfo(registrant: XRegistrantInfo,completionHandler: CompletionHandler) {
    // your  code.
    //
    //
    completionHandler(data: dataToReturn,success : true/false)
}
电话号码如下:

storeRegistrationInfo(registrant, { (data,success) -> Void in
    //onCompletion the code will go here
    if success {
        // success
    } else {
        // fail
    }
})

代码中的问题是这里的一行:

task.resume()
finished(apiResult)
您应该删除对
finished
完成处理程序的调用,因为在获得响应后,应该在已放置的位置调用该处理程序


另一个改进建议是简化字段验证代码,以使用
guard
语句。

谢谢!看来已经修好了!我会按照你关于守卫声明的建议……我在上面说“似乎”,因为在显示“欢迎…”警报后,应用程序现在正在崩溃。但是我不知道这是否有关系。为了结束这个问题以及其他遇到同样问题的人,感谢我意识到
showXAlert()
试图从主线程以外的线程发出警报。这就是造成坠机的原因谢谢Moin。我刚刚对
typealias
做了一些快速的研究。您建议这样做是为了提高代码的可维护性/可读性吗?你为什么要检查xUserAppResult实例的
success:Bool
属性,而不是我现在看到的
success:Int
属性?如果返回类型只是在两个值之间切换,那么我通常更喜欢使用Bool,如果它的顺序大于但在一个序列中,那么使用enum