Swift如何知道layoutIfNeeded()后布局是否完成

时间:2018-04-30 15:40:26

标签: ios swift3 uiview

我有一个用于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?

非常感谢提前。

2 个答案:

答案 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也不太可能是合适的;研究使用表视图或集合视图。作为一般规则,您应该尝试仅对当前屏幕上的任何内容具有活动控件,并且这两个视图都提供了非常容易管理该活动集的方法。每个视图都有内存占用,因为视图内容是缓冲的 - 如果不必要地挤压内存,您将损害自己和其他正在运行的应用程序的性能。