JSON 调用后调度组不会阻塞
Dispatch group won't block after JSON call
我试图在填充 TableCell 之前让 JSON 调用 return,但是作为 swift 的新手,我无法使用调度进行调用块队列....任何人都可以告诉我如何让它在下面发布的代码中的 group.wait()
行停止。
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let queue:DispatchQueue = DispatchQueue.global()
let group:DispatchGroup = DispatchGroup()
Alamofire.request("http://localhost:3000/locations.json").responseJSON { response in
group.enter()
//print(response.request) // original URL request
//print(response.response) // HTTP URL response
//print(response.data) // server data
//print(response.result) // result of response serialization
guard response.result.error == nil else{
print("Error: unable to get a list of locations.")
return
}
if let JSON = response.result.value {
// print("JSON: \(JSON)")
if let result = response.result.value as? [[String: Any]] {
nameArray = result.map { ([=11=]["name"] as? String)! }
print(nameArray[0])
}
}
group.leave()
}
group.notify(queue: queue) {
// This closure will be executed when all tasks are complete
print("All tasks complete")
}
// synchronize on task completion by waiting on the group to block the current thread.
print("block while waiting on task completion")
let _ = group.wait()
print("continue")
let cell = tableView.dequeueReusableCell(withIdentifier: "Picture", for: indexPath)
cell.textLabel?.text = LocationData[indexPath.row].name
print (LocationData[indexPath.row].name)
print(indexPath.row)
// cell.textLabel?.text = nameArray[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier: "Detail") as? DetailViewController {
vc.selectedImage = pictures[indexPath.row]
navigationController?.pushViewController(vc, animated: true)
}
}
你必须在执行你的请求之前调用group.enter()
,而不是在闭包内。
但是因为 Alamofire 使用主队列作为它的完成处理程序,如果你在主队列上 wait
直到完成处理程序调用 leave()
,你就会死锁。如果你真的想使用这个 "wait" 模式,你必须指定 request
应该使用那个后台队列作为它的完成处理程序。
话虽如此,虽然它在直觉上对 wait
很有吸引力,但这并不是对它的恰当用法。 (使用信号量的其他逻辑上等效的解决方案也不会。)
您应该发起网络请求,然后异步更新单元格。但是 cellForRowAtIndexPath
不应该等待网络请求。
我本来打算建议替代实现,但还不完全清楚你想做什么(现在,你正在为 table 的每一行做另一个网络请求,这不似乎不对)。 LocationData
从哪里来?假设你真的想做一个请求来获取位置的名称,你会将该请求移动到 viewDidLoad
,然后在完成处理程序中调用 tableView.reload()
。
var locations: [String]?
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request("http://localhost:3000/locations.json").responseJSON { response in
guard response.result.error == nil else{
print("Error: unable to get a list of locations.")
return
}
if let result = response.result.value as? [[String: Any]] {
self.locations = result.map { [=10=]["name"] as! String }
self.tableView.reloadData()
}
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return locations?.count ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Picture", for: indexPath)
cell.textLabel?.text = locations?[indexPath.row]
return cell
}
我试图在填充 TableCell 之前让 JSON 调用 return,但是作为 swift 的新手,我无法使用调度进行调用块队列....任何人都可以告诉我如何让它在下面发布的代码中的 group.wait()
行停止。
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let queue:DispatchQueue = DispatchQueue.global()
let group:DispatchGroup = DispatchGroup()
Alamofire.request("http://localhost:3000/locations.json").responseJSON { response in
group.enter()
//print(response.request) // original URL request
//print(response.response) // HTTP URL response
//print(response.data) // server data
//print(response.result) // result of response serialization
guard response.result.error == nil else{
print("Error: unable to get a list of locations.")
return
}
if let JSON = response.result.value {
// print("JSON: \(JSON)")
if let result = response.result.value as? [[String: Any]] {
nameArray = result.map { ([=11=]["name"] as? String)! }
print(nameArray[0])
}
}
group.leave()
}
group.notify(queue: queue) {
// This closure will be executed when all tasks are complete
print("All tasks complete")
}
// synchronize on task completion by waiting on the group to block the current thread.
print("block while waiting on task completion")
let _ = group.wait()
print("continue")
let cell = tableView.dequeueReusableCell(withIdentifier: "Picture", for: indexPath)
cell.textLabel?.text = LocationData[indexPath.row].name
print (LocationData[indexPath.row].name)
print(indexPath.row)
// cell.textLabel?.text = nameArray[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier: "Detail") as? DetailViewController {
vc.selectedImage = pictures[indexPath.row]
navigationController?.pushViewController(vc, animated: true)
}
}
你必须在执行你的请求之前调用group.enter()
,而不是在闭包内。
但是因为 Alamofire 使用主队列作为它的完成处理程序,如果你在主队列上 wait
直到完成处理程序调用 leave()
,你就会死锁。如果你真的想使用这个 "wait" 模式,你必须指定 request
应该使用那个后台队列作为它的完成处理程序。
话虽如此,虽然它在直觉上对 wait
很有吸引力,但这并不是对它的恰当用法。 (使用信号量的其他逻辑上等效的解决方案也不会。)
您应该发起网络请求,然后异步更新单元格。但是 cellForRowAtIndexPath
不应该等待网络请求。
我本来打算建议替代实现,但还不完全清楚你想做什么(现在,你正在为 table 的每一行做另一个网络请求,这不似乎不对)。 LocationData
从哪里来?假设你真的想做一个请求来获取位置的名称,你会将该请求移动到 viewDidLoad
,然后在完成处理程序中调用 tableView.reload()
。
var locations: [String]?
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request("http://localhost:3000/locations.json").responseJSON { response in
guard response.result.error == nil else{
print("Error: unable to get a list of locations.")
return
}
if let result = response.result.value as? [[String: Any]] {
self.locations = result.map { [=10=]["name"] as! String }
self.tableView.reloadData()
}
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return locations?.count ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Picture", for: indexPath)
cell.textLabel?.text = locations?[indexPath.row]
return cell
}