我想显示UITableView
中的服务器延迟,唯一的问题是ping结果处理程序不会在DispatchQueue
下运行
let dispatch_queue = DispatchQueue(label: "PingQueue", qos: .background)
dispatch_queue.async {
let client = SimplePingClient()
client.pingHostname(hostname: self.Servers[indexPath.row].Address, andResultCallback: { result in
guard let r = result as? String else {
DispatchQueue.main.async {
cell.lblLatency.text = "Timeout"
}
return
}
DispatchQueue.main.async{
cell.lblLatency.text = r + " ms"
}
})
}
andResultCallback
根本不会打来(我不知道为什么!?)
答案 0 :(得分:2)
首先,您需要注意一些有关现有代码的信息。
您对dispatch_queue.async
的调用正在进行client
的初始化,并且client.pingHostname
的调用在dispatch_queue.async
队列上运行。请注意,由于pingHostname
是异步API,因此它几乎立即返回,并不意味着竞争处理程序将在dispatch_queue
上运行。
dispatch_queue.async
可能没有意义。假设客户端初始化是一个轻量级的,不依赖IO的任务(即它不进行任何网络调用),并假设pingHostname是轻量级的(鉴于它是其自身的异步功能,则几乎可以肯定是这样),那么就没有理由不能使用dispatch_queue.sync
调用,甚至不能直接从当前线程进行这些调用。它可能几乎一样快,甚至可能更快(因为异步调用使转义分析变得更加困难,并限制了编译器的优化)。这样做还有一个好处,那就是消除了“如果在完成下一件事情之前完成此操作?或者如果在另一件事之前又完成了该操作,该怎么办?”的担忧。您提供了异步pingHostname
API的闭包,它可以自由地在希望的任何线程/队列上运行,我们称它为队列/线程X
。 API文档可能会对此有所启发。
从队列/线程X
的上下文中,您对DispatchQueue.main
进行异步调用。这是对的;可可的目的是使所有UI更新都必须始终在主线程中进行。
如果您打算在dispatch_queue
上运行竞赛处理程序代码,则您必须:
提供dispatch_queue
作为pingHostname
API的参数,以便它可以在您的队列上运行竞争处理程序,而不是采用其他默认值。当然,这是API必须具有的功能。
从竞争处理程序中的线程/队列dispatch_queue.sync
对X
进行自己的调用。
在没有DispatchQueue
参数的情况下,这是我的写法:
pingQueue = DispatchQueue(label: "PingQueue", qos: .background)
let client = SimplePingClient()
client.pingHostname(
hostname: self.Servers[indexPath.row].Address, // This is jank, but I'm ignoring it for now
andResultCallback: { _latency in
pingQueue.sync {
print("Do some stuff on pingQueue")
DispatchQueue.main.sync { // enter main queue for UI updates
cell.lblLatency.text = (_latency as? String).map { $0 + " ms" } ?? "Timeout"
}
}
}
)
答案 1 :(得分:1)
在cellForRowAt
内部调用此名称是不正确的。您的ViewController结果数组中应该有一个地方
var results = [String]()
现在,获取结果到其他地方,而不是cellForRowAt
中。为此创建自定义方法,或使用自定义模型。
更好的情况是,如果您的pingHostname
方法返回了所有结果,然后您只分配了results
数组,然后重新加载TableView的数据
client.pingHostname { results in
if let r = result as? [String] {
self.results = r
self.tableView.reloadData()
}
}
也将此results
数组用作TableView数据源方法的源
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return results.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
cell.lblLatency.text = results[indexPath.row]
...
}
答案 2 :(得分:0)
由于您的ping客户端在完成操作之前已被释放,因此未调用结果回调。
使client
成为实例变量而不是局部变量。完成操作后,将其设置为nil
。