在解释响应之前,如何确保此功能完成?

Posted

技术标签:

【中文标题】在解释响应之前,如何确保此功能完成?【英文标题】:How Can I Make Sure This Function Completes Before I Interpret The Response? 【发布时间】:2017-02-03 07:25:18 【问题描述】:

我对 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() 返回一个 XUserAPIResult 结构,然后根据 XUserAPIResult struct 显示适当的警报strong>XUserAPIResult 的成功属性。

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

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

如何确保@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)
       

...仅在解析 JSON 并填充 UserAPIResult 结构并传回后才调用?

谢谢。

【问题讨论】:

【参考方案1】:

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

task.resume()
finished(apiResult)

您应该删除对 finished 完成处理程序的调用,因为在收到响应后,应该在已经放置它的位置调用该处理程序。

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

【讨论】:

谢谢!这似乎已经解决了它!我会听从你关于守卫声明的建议...... ...我在上面说“似乎”是因为在显示“欢迎...”警报后应用程序现在崩溃了。我不知道这是否相关。 为了结束这个问题以及其他遇到同样问题的人,感谢this thread 我意识到showXAlert() 试图从主线程以外的线程显示警报。这就是导致崩溃的原因。【参考方案2】:

试试下面的

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
    
)

【讨论】:

谢谢莫恩。我刚刚对typealias 做了一些快速研究。您是否建议这样做以提高代码的可维护性/可读性?您是否有任何理由检查 success: Bool 与我目前拥有的 XUserAPIResult 实例的 success: Int 属性? 如果返回类型只是要在 2 个值之间切换,那么我通常更喜欢使用 bool,如果它大于但在一个序列中然后枚举

以上是关于在解释响应之前,如何确保此功能完成?的主要内容,如果未能解决你的问题,请参考以下文章

如何等待此功能完成?

如何在开始下一个功能之前等待功能完成?

Git-Flow - 在发布完成之前创建新功能

在前一个异步操作完成之前,在此上下文上启动了第二个操作。使用“等待”来确保

如何确保在完成写入文件之前不读取文件

js写cookie,如何完成其保存功能