我有一个用于iPad的数学程序,使用Big Number库进行计算,然后根据这些计算更新UIView(myView)中最多20,000 UILabel的数组。
计算可能需要大约5秒钟,在此期间每个UILabel的backgroundColor都设置为一种颜色。因为屏幕上什么都没发生,所以我有一个闪烁的UILabel inProgressLabel告诉用户系统正在计算。然后我调用layoutIfNeeded,并认为当它完成时,屏幕将被更新。最后,我关掉闪烁的UILabel。
这是伪代码:
inProgressLabel.turnOnBlinking()
for row in 0..<rowCount
{
for col in 0..<colCount
{
// perform some calculation
let z = buttonArray[row][col].performCalculation()
//now set the Label background based on the result of the calculation
buttonArray[row][col].setLabelBackground(z)
}
}
myView.layoutIfNeeded()
inProgressLabel.turnOffBlinking()
我的理解是layoutIfNeeded()是同步的。因此,屏幕将更新,然后,只有这样,闪烁的inProgressLabel才会被关闭。但是,inProgressLabel实际上在调用layoutIfNeeded之后立即关闭,然后UILabels数组可能需要另外五秒钟来更新。
我认为可能会发生这种情况,因为更新发生在另一个线程中。如果是这样,有没有办法知道UIView和UILabel数组何时完成更新(显示),以便我可以关闭闪烁的UILabel?
非常感谢提前。
答案 0 :(得分:1)
你可以尝试
let dispatchGroup = DispatchGroup()
for row in 0..<rowCount
{
for col in 0..<colCount
{
dispatchGroup.enter()
self.doCalcAndUpdateLbl(index: i) { (finish) in
dispatchGroup.leave()
}
}
}
dispatchGroup.notify(queue: .main) {
myView.layoutIfNeeded()
inProgressLabel.turnOffBlinking()
}
答案 1 :(得分:1)
UIKit控件不是线程安全的。从后台更新UILabel会产生未定义的行为。
layoutIfNeeded
执行任何待处理的布局任务并返回。对于您将来可能计划进行的任何更改,它没有神奇的远见。
您需要将工作安排在主队列之外,并确保在完成后将结果推回到主线程。如果分别发送各种计算是有意义的,请使用Sh_Khan建议的调度组。否则,只考虑在单个块中执行后台计算,然后从那里跳回主队列。
20,000 UILabels也不太可能是合适的;研究使用表视图或集合视图。作为一般规则,您应该尝试仅对当前屏幕上的任何内容具有活动控件,并且这两个视图都提供了非常容易管理该活动集的方法。每个视图都有内存占用,因为视图内容是缓冲的 - 如果不必要地挤压内存,您将损害自己和其他正在运行的应用程序的性能。