等待异步函数调用完成 [英] Waiting for Asynchronous function call to complete

查看:132
本文介绍了等待异步函数调用完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我之前已经问过这个问题,但是所有的解决方案都不适用于我。

I know this question has been asked before, but all solutions do not work for me.

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

I have a function with sends parameters to an API, and returns the data as a list, I have a UITableView set up to use that list, but it runs before the list is assigned to a variable.

代码:

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.


}

如果不是,我将不胜感激立即投票重复,这是我尝试过的。

I would appreciate it if it is not immediately voted as a duplicate, here is what I have tried.


  1. 派遣小组

  2. 信号量时间

  3. 运行变量

  4. 包括 self.tableofItems.delegate = self& self.tableofItems.dataSource = self in fetchItems {(str)in part。

  1. Dispatch groups
  2. Semaphore timing
  3. running variables
  4. including self.tableofItems.delegate = self & self.tableofItems.dataSource = self in the fetchItems{ (str) in part.

编辑:
已请求提取物品,

Fetch items has been requested,

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!))


推荐答案

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

You can't - and shouldn't - wait until an async call to complete. You need to study async programming until you understand it.

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

An async function accepts a job to do, and returns immediately, before the job is done.

你通常会编写一个异步函数来获取一个完成处理程序,这是一个你希望在异步任务完成时运行的代码块。

in Swift you usually write an async function to take a completion handler, which is a block of code that you want to be run one the async task is complete.

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

I have a project called Async_demo (link) on Github that illustrates this. It implements a DownloadManager class that handles async downloads.

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

The key part is the function downloadFileAtURL(), which should more properly be named downloadDataAtURL, since it returns in-memory data rather than a file.

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

I created that function to take a completion handler as a parameter:

/**
 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()函数的完成处理程序,但是在主线程上。

It uses an NSURLSession to download a block of data from the specified URL. The data request call I use takes a completion handler that gets executed on a background thread. In the completion handler that I pass to the data task, I invoke the completion handler that's passed in to the downloadFileAtURL() function, but on the main thread.

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

The code you posted is kind of confusing. It isn't clear which part is the async function, what the flow is, or what data is needed to display your table view.

如果你重写你的函数那么async工作以获取完成块,然后您可以在完成块中调用 tableView.reloadData()。 (确保在主线程上执行调用。)

If you rewrite your function that does async work to take a completion block then you could call tableView.reloadData() in your completion block. (Make sure that call is performed on the main thread.)

正如其他人所说的那样,您需要编辑您的问题以显示 fetchItems()函数的代码。

As others have said, you need to edit your question to show the code for your fetchItems() function.

我猜这个函数是执行异步工作的函数,而后面的块是异步执行的完成处理程序。如果是这样,你应该像这样重构你的代码:

I'm guessing that that function is the one that does the Async work, and that the block after it is a completion handler that gets performed asynchronously. If so, you should probably refactor your code like this:

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

这篇关于等待异步函数调用完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆