等待asynchronous函数调用完成
我知道这个问题之前已经被问过,但所有的解决scheme都不适合我。
我有一个函数发送参数到一个API,并返回数据作为列表,我有一个UITableView设置使用该列表,但它运行之前列表分配给一个variables。
码:
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. }
如果不立即投票表决,我将不胜感激,这是我所尝试过的。
- 派遣小组
- 信号量计时
- 运行variables
- 包括
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!))
您不能 – 也不应该 – 等到asynchronous调用完成。 你需要学习asynchronous编程,直到你理解它。
asynchronous函数接受要做的工作,并在作业完成之前立即返回。
在Swift中,你通常编写一个asynchronous函数来完成一个完成处理程序,这是一个你想运行一个asynchronous任务完成的代码块。
我有一个名为Async_demo (链接)在Github上的项目,说明了这一点。 它实现了一个处理asynchronous下载的DownloadManager类。
关键部分是函数downloadFileAtURL()
,它应该更正确地命名为downloadDataAtURL,因为它返回的是内存数据而不是文件。
我创build了这个函数来完成处理程序作为参数:
/** 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()
函数的完成处理程序,但在主线程上。
你发布的代码有点令人困惑。 目前还不清楚哪个部分是asynchronousfunction,stream程是什么,或者需要哪些数据来显示你的表格视图。
如果你重写asynchronous的函数来完成一个完成块,那么你可以在完成块中调用tableView.reloadData()
。 (确保在主线程上执行调用。)
编辑:
正如其他人所说,你需要编辑你的问题,以显示你的fetchItems()
函数的代码。
我猜这个函数是Async的工作,并且它之后的块是一个asynchronous执行的完成处理程序。 如果是这样,你可能应该像这样重构你的代码:
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") }
您应该在loadView
的方法中加载列表的数据,以便在UITableView
读取之前加载它。
有时候, viewDidLoad
会慢一点。 一般来说,人们会在loadView
的方法中初始化list或sth的数据,以确保在创buildview
之前数据已经完成。