当前位置: 首页 > 面试题库 >

等待异步函数调用完成

燕凯旋
2023-03-14
问题内容

我知道这个问题以前曾被问过,但是所有解决方案都不适合我。

我有一个将参数发送到API的函数,并以列表的形式返回数据。我有一个UITableView设置为使用该列表,但是它在列表分配给变量之前运行。

码:

var functionResult = [String]()
override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        //gradesscrollView.contentSize.height = 3000
        fetchItems{ (str) in

            var returnedItems = [String]()

            let result = self.convertoArray(itemstoPass: str!)
            for i in result{
                functionResult.append(i)
            }
        }

        self.tableofItems.delegate = self
        self.tableofItems.dataSource = self //Data source is set up to use functionResult, however functionResult is empty before fetchItem runs.


}

如果不立即将其作为重复投票,我将不胜感激,这是我尝试的方法。

  1. 派遣组
  2. 信号量计时
  3. 运行变量
  4. 其中包括self.tableofItems.delegate= self和self.tableofItems.dataSource= self fetchItems{ (str) in

编辑:要求提取项目,

func fetchItems(completionHandler: @escaping (String?) -> ()) -> () {
        let headers = [
            "Content-Type": "application/x-www-form-urlencoded"
        ]
        //Switch to keychain
        let username = UserDefaults.standard.object(forKey: "username") as! String?
        let password = UserDefaults.standard.object(forKey: "password") as! String?

        let usernametoSend = username!
        let passwordtoSend = password!

        print(usernametoSend)
        print(passwordtoSend)
        let parameters: Parameters = [
            "username": usernametoSend,
            "password": passwordtoSend
        ]

        Alamofire.request("https://www.mywebsite.com/API/getItems", method: .post, parameters: parameters, headers: headers)
            .responseString { response in
                completionHandler(String(response.result.value!))

问题答案:

您不能-也不应该-等到异步调用完成。您需要学习异步编程,直到您了解它为止。

异步函数接受要执行的作业,并在作业完成之前立即返回。

在Swift中,您通常会编写一个异步函数来获取完成处理程序,这是您要在异步任务完成后运行的代码块。

我在Github上有一个名为 Async_demo
(链接)的项目来说明这一点。它实现了处理异步下载的DownloadManager类。

关键部分是函数downloadFileAtURL(),应将其更恰当地命名为downloadDataAtURL,因为它返回内存中的数据而不是文件。

我创建了该函数以将完成处理程序作为参数:

/**
 This function demonstrates handling an async task.
 - Parameter url The url to download
 - Parameter completion: A completion handler to execute once the download is finished
 */

  func downloadFileAtURL(_ url: URL, completion: @escaping DataClosure) {

    //We create a URLRequest that does not allow caching so you can see the download take place
    let request = URLRequest(url: url,
                             cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
                             timeoutInterval: 30.0)
    let dataTask = URLSession.shared.dataTask(with: request) {
      //------------------------------------------
      //This is the completion handler, which runs LATER,
      //after downloadFileAtURL has returned.
      data, response, error in

      //Perform the completion handler on the main thread
      DispatchQueue.main.async() {
        //Call the copmletion handler that was passed to us
        completion(data, error)
      }
      //------------------------------------------
    }
    dataTask.resume()

    //When we get here the data task will NOT have completed yet!
  }
}

它使用NSURLSession从指定的URL下载数据块。我使用的数据请求调用需要在后台线程上执行的完成处理程序。在传递给数据任务的完成处理程序中,我调用传递给downloadFileAtURL()函数但在主线程上的完成处理程序。

您发布的代码有点令人困惑。目前尚不清楚哪个部分是异步功能,流程是什么或显示表视图需要什么数据。

如果您重写执行异步工作的函数以获取完成块,则可以调用tableView.reloadData()完成块。(确保在主线程上执行调用。)

编辑:

正如其他人所说,您需要编辑问题以显示fetchItems()功能代码。

我猜想那个函数是做异步工作的那个函数,而它后面的那个块是一个异步执行的完成处理程序。如果是这样,您可能应该这样重构代码:

var functionResult = [String]()
override func viewDidLoad() {
        super.viewDidLoad()

        //I moved these lines above the call to fetchItems to make it clear
        //that they run before fetchItems' completion closure is executed
        self.tableofItems.delegate = self
        self.tableofItems.dataSource = self //Data source is set up to use functionResult, however functionResult is empty before fetchItem runs.

        print("Step 1")
        fetchItems{ (str) in

            var returnedItems = [String]()

            let result = self.convertoArray(itemstoPass: str!)
            for i in result{
                functionResult.append(i)
            }
            print("Step 3")
            DispatchQueue.main.async() {
              tableview.reloadData() //Do this from the main thread, inside the closure of `fetchItems()`
            }
        }

        print("Step 2")
}


 类似资料:
  • 我试图为从服务调用异步函数的函数编写测试,但我一辈子都不知道如何让Jasmine在执行expect函数之前等待异步操作完成。 我试图使用Jasmine的“完成”功能,但我不知道如何实现它。 在本例中,只要 调用时,它立即跳转到expect并失败,因为异步操作尚未完成。

  • 问题内容: 嗨,我的脚本中有2个Ajax调用,我需要它们运行asnyc以节省时间,但是我需要第二个才能等待第一个完成。 有什么想法吗?谢谢 问题答案: 如果使用jQuery 1.5+,则可以使用jQuery 完成。诸如此类的东西(缩短了ajax的简洁性,只需像上面那样传递对象) 您不知道它们将以什么顺序返回,因此,如果您手动滚动此请求,则需要检查另一个请求的状态并等待它返回。

  • 所以我在Angular中开发了一个新组件,在ngOninit中我有以下异步函数。。。 这getUserProfile需要完成才能调用它。getPrivateGroup()和这个。需要先完成getPrivateGroup(),然后才能调用此函数。loadGroupPosts()。我知道我可以在异步请求的回调中编写这些函数,但我想知道是否有一种方法可以将它保存在ngOnInit中以保持其更干净? 有人

  • 我通读了Dart/flatter中的Async/Await/then,试图理解为什么aysnc函数中的Await不会等到完成后再继续。在我的UI中,有一个按钮调用一个异步方法来返回一个位置,该位置总是返回null,并且不等待函数完成。 该函数将调用推送到一个新的UI页面,该页面选择一个位置,并应返回一个结果。如何使该函数等待结果?我不是在使用异步吗?

  • 我正试图将图像上传到firebase存储,但调用该函数时,未执行wait以获取url。我错过了什么? 看看这个其他主题,我发现问题可能是“然后”,但我如何设置代码以等待url? 异步/等待/然后飞镖/颤振 谢谢

  • 问题内容: 我的代码在javascript中看起来像这样: 在完成所有这些异步调用之后,我想计算所有数组的最小值。 我要如何等待所有人? 我现在唯一的想法是拥有一个名为done的布尔数组,并在第i个回调函数中将done [i]设置为true,然后说while(不是全部都完成了){} 编辑:我想一个可能但很丑陋的解决方案是在每个回调中编辑完了的数组,然后如果每个回调中都设置了所有其他完成,则调用一个