我之前已经问过这个问题,但所有解决方案对我都不起作用。
我有一个函数发送参数到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.
}
如果不立即将其作为重复投票,我将不胜感激,这就是我所尝试过的。
self.tableofItems.delegate
= self& self.tableofItems.dataSource
部分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!))
答案 0 :(得分: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")
}
答案 1 :(得分:-2)
您应该使用loadView
方法加载列表数据,以便在UITableView
读取之前加载它。
有时,viewDidLoad
表现得有点慢。通常,人们会在loadView
的方法中初始化list或sth的数据,以确保在创建view
之前完成数据。