【问题标题】:How to delay asynchronous function and wait for completion block to execute? [duplicate]如何延迟异步函数并等待完成块执行? [复制]
【发布时间】:2017-05-18 04:38:01
【问题描述】:

我有这个函数,它有一个完成块,函数异步返回而不等待完成。

我希望我的函数延迟它的返回,直到它的完成块完成。我更改了回调函数,但它不起作用,我是 swift 新手,所以对 GCD 知之甚少,他们的 API 也发生了很大变化。

 func authenticateCredentials(usernameString: String, passwordString: String, completion: @escaping (Bool)-> Void)  {


            var boolVal: Bool = false
            client.invokeAPI("AuthenticateAndFetchData",
                             body: nil,
                             httpMethod: "GET",
                             parameters: ["userid": usernameString,"password":passwordString],
                             headers: nil)
            {
                (result, response, error) -> Void in
                if let err = error {
                    print("ERROR ", err)

                } else if let res = result {
                    let jsonArray = res as! NSArray
                    // print(jsonArray)
                    for value in jsonArray[0] as! NSDictionary {
                        let jsonstring = value.value as! String
                        NetworkService.jsonResponse = jsonstring
                        if let data = jsonstring.data(using: .utf8) {
                            if let content = try? JSONSerialization.jsonObject(with: data, options: []),
                                let array = content as? [[String: Any]]
                            {
                                for jsondict in array {

                                    let auth = jsondict["IsAuth"]! as! String
                                    print(type(of: auth))
                                    print(auth)
                                    boolVal = (auth == "true") ? true : false
                                    self.isAuth = boolVal
                                    print(boolVal)

                                    completion(boolVal) // callback here
                                }
                            }
                        }
                    }

                }
            }

      }

我在这样的登录操作中从我的 viewController 调用这个函数。

 // After login button is pressed
    @IBAction func loginButtonTapped(_ sender: UIButton) {

        let userid = userIDtxt.text
        let password = userpasswordtxt.text
        //Display an alert if no text is entered 
        if (userid?.isEmpty)! || (password?.isEmpty)! {
            displayAlertMessage("Please enter userid/password")
        }
            // take this userid and password and authenticate from sql server and move to 

        else {
            // Run the spinner to show the task is in progress
            print("\(userid)" + " " + "\(password)")
            nw.authenticateCredentials(usernameString: userid!, passwordString: password!){
                (boolVal) in

                    self.nw.isAuth = boolVal


            }

            showActivityIndicatory(uiview: view)

            if nw.isAuth == true {


            // User authenticated

            }
            else {

            // wrong user
            }

        }


    }

所以这里authenticateCredentials函数预先返回,它返回false,所以当我第一次点击我的登录按钮时,我收到false,当我第二次点击它时,我收到true。我想在第一次点击时接收真实和认证的用户。

【问题讨论】:

  • 简短回答:你不能也不应该那样做。您需要了解异步代码和完成处理程序的工作原理。

标签: ios swift asynchronous callback synchronization


【解决方案1】:

这应该可以 - 回调后更新你的 UI

nw.authenticateCredentials(usernameString: userid!, passwordString: password!){ [weak self] (boolVal) in
        guard let `self` = self else {
             return
        } //to avoid memory leak
        self.nw.isAuth = boolVal

        showActivityIndicatory(uiview: view)

        if nw.isAuth == true {


            let userData = User.getUserData()
            print("FirstName: \(userData.LastName)")
            showActivityIndicatory(uiview: view)

            displayAlertMessage("User authenticated.")
            hideActivityIndicator(uiView: view)
            self.saveData(userData: userData)

            print("Welcome123 \(userid)")

        }
        else {

            displayAlertMessage("Wrong Username/Password. Please try again.")
            hideActivityIndicator(uiView: view)
        }
    }

基本思路:

func asyncA(handlerA: () -> ()) {
   asyncB({
       handlerA()
   })
}

func asyncB(handlerB: () -> ()) {
    handlerB()
}

func uiviewcontrollerfunc() {
    asyncA({ [weak self] in
       //update ui
  })
}

【讨论】:

  • 到目前为止,我只是弹出一个警报,并在控制台上打印,我现在应该把更新 UI 语句放在哪里?因为当我第一次点击登录时,会弹出“错误的用户名/密码”消息,当我点击两次登录时,它会进行身份验证。
  • 我有类似的请求结构,这里的想法是:你的UIViewController调用funcA(handler: someHandlerA),它调用funcB(handler: someHandlerB),在funcB里面有异步服务器请求,它有它自己的@987654327 @。您应该在serverDataHandler 中调用someHandlerB,然后在someHandlerB 中调用someHandlerA,并将所有UI 更新放在someHandlerA 中。这只会在所有功能执行后才导致 UI 更新,如果我理解,你想要实现什么。
  • 就我而言,someHanlerA 在哪里?我的 UIViewController 调用 loginButtonTapped 函数,该函数调用具有异步服务器请求的 AuthenticateCredentials,它有自己的 serverDataHandler。我能理解的是,您希望我回调 AuthenticateCredentials 处理程序。但就我而言,someHandlerA 是什么?有点混乱,感谢您的帮助。
  • 在你的情况下,我假设你的UIViewController 调用AuthenticateCredentials,它有它的处理程序,然后它调用服务器,得到响应,在serverHandler 你调用AuthenticateCredentialsHanler,然后更新你的 UI,因为你的服务器已经响应并且你已经更新了你的模型。顺便说一句,我还建议您阅读有关AlamofireSwiftyJSON 的信息,它们会让您的工作更轻松。
  • completion(boolVal) 我在其中调用了 authenticateCredentials 的 completionHandler。我如何在 UIViewController 中调用它。
猜你喜欢
  • 2019-11-07
  • 1970-01-01
  • 1970-01-01
  • 2021-11-26
  • 2019-06-16
  • 1970-01-01
  • 1970-01-01
  • 2019-12-30
  • 1970-01-01
相关资源
最近更新 更多