Swift 如何知道布局是否在 layoutIfNeeded() 之后完成
Swift How to know if layout finished after layoutIfNeeded()
我有一个 iPad 的数学程序,使用大数库进行计算,然后根据这些计算更新 UIView (myView) 中最多包含 20,000 个 UILabel 的数组。
计算可能需要大约 5 秒,在此期间,每个 UILabel 的 backgroundColor 都设置为一种颜色。因为屏幕上没有发生任何事情,所以我在 ProgressLabel 中有一个闪烁的 UILabel 通知用户系统正在计算。然后我调用 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 后立即关闭,然后 UILabel 数组可能还需要五秒钟才能更新。
我想这可能是因为更新发生在不同的线程中。如果是这样,有没有办法确定 UIView 和 UILabel 数组何时完成更新(显示),以便我可以关闭闪烁的 UILabel?
非常感谢。
你可以试试
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()
}
UIKit 控件不是线程安全的。从后台更新 UILabels 会产生未定义的行为。
layoutIfNeeded
执行任何未决的布局任务和 returns。对于您未来可能计划进行的任何更改,它都没有神奇的预见性。
您需要将工作安排在主队列之外进行,并确保完成后将结果推回主线程。如果分派各种计算单独发生是有意义的,请使用 Sh_Khan 建议的分派组。否则考虑只在一个块中执行后台计算,然后从那里跳回主队列。
20,000 个 UILabel 也不太可能合适;考虑使用 table 视图或集合视图。作为一般规则,您应该尝试只对当前屏幕上的任何内容进行活动控制,并且这两种视图都提供了非常容易管理该活动集的方法。每个视图都有内存占用,因为视图的内容是缓冲的——如果您不必要地挤压内存,您将损害您自己和其他 运行 应用程序的性能。
我有一个 iPad 的数学程序,使用大数库进行计算,然后根据这些计算更新 UIView (myView) 中最多包含 20,000 个 UILabel 的数组。
计算可能需要大约 5 秒,在此期间,每个 UILabel 的 backgroundColor 都设置为一种颜色。因为屏幕上没有发生任何事情,所以我在 ProgressLabel 中有一个闪烁的 UILabel 通知用户系统正在计算。然后我调用 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 后立即关闭,然后 UILabel 数组可能还需要五秒钟才能更新。
我想这可能是因为更新发生在不同的线程中。如果是这样,有没有办法确定 UIView 和 UILabel 数组何时完成更新(显示),以便我可以关闭闪烁的 UILabel?
非常感谢。
你可以试试
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()
}
UIKit 控件不是线程安全的。从后台更新 UILabels 会产生未定义的行为。
layoutIfNeeded
执行任何未决的布局任务和 returns。对于您未来可能计划进行的任何更改,它都没有神奇的预见性。
您需要将工作安排在主队列之外进行,并确保完成后将结果推回主线程。如果分派各种计算单独发生是有意义的,请使用 Sh_Khan 建议的分派组。否则考虑只在一个块中执行后台计算,然后从那里跳回主队列。
20,000 个 UILabel 也不太可能合适;考虑使用 table 视图或集合视图。作为一般规则,您应该尝试只对当前屏幕上的任何内容进行活动控制,并且这两种视图都提供了非常容易管理该活动集的方法。每个视图都有内存占用,因为视图的内容是缓冲的——如果您不必要地挤压内存,您将损害您自己和其他 运行 应用程序的性能。