等待异步函数调用完成
Posted
技术标签:
【中文标题】等待异步函数调用完成【英文标题】:Waiting for Asynchronous function call to complete 【发布时间】:2016-12-18 15:19:36 【问题描述】:我知道以前有人问过这个问题,但所有解决方案都不适用于我。
我有一个向 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.
如果它没有立即被投票为重复,我将不胜感激,这是我尝试过的。
-
调度组
信号量计时
运行变量
在
fetchItems (str) in
部分中包括self.tableofItems.delegate
= self 和self.tableofItems.dataSource
= self。
编辑: 已请求获取项目,
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!))
【问题讨论】:
你有没有试过在获取项目后在主线程中重新加载表格视图? 显示fetchItems()
implementation。
并且:tableofItems.reloadData()
直接在您的 for
循环之后。
shallowThought,不幸的是 reloadData() 不起作用,我在重新加载打印语句之前验证了该列表已填充
【参考方案1】:
您不能 - 也不应该 - 等到异步调用完成。你需要学习异步编程,直到你理解为止。
异步函数接受要执行的作业,并在作业完成之前立即返回。
在 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")
【讨论】:
对不起,我对 Swift 很陌生 但是,还有吗?我有点需要为程序做这件事,我来自 Python 背景,一切都是一行一行的 查看我的答案的编辑。我对您的代码在做什么进行了有根据的猜测,并根据该猜测提供了解决方案。 Duncan C,你的代码成功了!对不起,如果这个问题很愚蠢。我对应用程序开发非常陌生,我很高兴学习。我希望有一天我不必那么频繁地问有关 Stack Overflow 的问题。非常感谢您的帮助! 好的,为什么要投反对票?如果您认为我的回答有待改进,请发表评论说明。我正在努力提供帮助。【参考方案2】:您应该在loadView
的方法中加载列表的数据,以便在UITableView
读取之前提前加载。
有时,viewDidLoad
执行速度有点慢。一般人们会在loadView
的方法中初始化list或某某的数据,以确保数据在view
创建之前完成。
【讨论】:
我尝试添加 loadView 功能,但问题仍然存在 你实现了UITableView的相关方法吗?比如有多少rows
,有多少cells
。
对不起,这个答案没有意义,并且提供了误导性信息。
实现loadView()
实际上并不常见,如果你不知道它的作用,就会充满问题,不要打电话给super.loadView()
为什么你对我的回答投了反对票?有些问题需要尝试才能解决。以上是关于等待异步函数调用完成的主要内容,如果未能解决你的问题,请参考以下文章