为什么这段添加子视图的代码要按这个顺序执行?

Why is this code to add a subview executing in this sequence?

我正在长按后显示一个小视图 (iconsContainerView),我不明白为什么 handleLongPress(gesture:) 中的代码会以现在的方式执行。据我了解,它应该从上到下,每一行都应该 运行 立即。意思是 view.addSubview(iconsContainerView) 运行 秒后,视图应该显示在屏幕的左上角,因为它的不透明度尚未设置为 0。

所以,编写的代码(一旦手势开始)似乎视图将显示在左上角的屏幕上,然后在转换时移动,然后消失(当不透明度设置为 0 时) ,然后在不透明度设置为 1 时重新出现在动画中。但是发生的情况是,在代码到达动画块之前,视图甚至不会显示。

所以,一切都按照我想要的方式运行——我确实希望子视图在长按后淡入。但我只是想了解这背后的原因以及为什么每一行代码都没有立即执行(或者至少以这种方式显示在屏幕上)。它在主线程上是 运行ning,我在其中放置了断点并验证了这些行的顺序是 运行ning。

class ViewController: UIViewController {

    let iconsContainerView: UIView = {
        let containerView = UIView()
        containerView.backgroundColor = .red

        containerView.frame = CGRect(x: 0, y: 0, width: 200, height: 100)

        return containerView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        setUpLongPressGesture()
    }

    fileprivate func setUpLongPressGesture() {
        view.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress)))
    }

    @objc func handleLongPress(gesture: UILongPressGestureRecognizer) {
        print("Long gesture", Date())

        if gesture.state == .began {
            view.addSubview(iconsContainerView)

            let pressedLocation = gesture.location(in: view)
            let centeredX = (view.frame.width - iconsContainerView.frame.width) / 2

            iconsContainerView.transform = CGAffineTransform(translationX: centeredX, y: pressedLocation.y - iconsContainerView.frame.height)

            iconsContainerView.alpha = 0

            UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {


                self.iconsContainerView.alpha = 1

            })


        } else if gesture.state == .ended {
            iconsContainerView.removeFromSuperview()
        }
    }

}

我认为您希望您的代码像这样运行

you add a subview
system draws the view on the screen
you update the views transform
system redraws the view on the screen
you updates the views alpha
system redraws the view on the screen

由于您的代码 运行 在主线程上运行,系统绘图代码也在主线程上 运行 运行,因此它们不可能 运行 在同时或在两者之间翻转。

实际情况是,您的应用在后台有一个始终 运行ning 的循环(RunLoop)。最简单的思考方式是它

handles input
draws views to the screen
repeat

您的代码将属于 handle input 部分。因此,整个方法必须完成 运行ning,然后循环才能进入下一步,即将视图绘制到屏幕上。这也是为什么不要在主线程上做很多工作很重要,如果你的方法需要一秒钟到 运行 这将意味着应用程序无法绘制到屏幕或处理 1 个整体的额外输入第二,这会使应用程序看起来冻结。


旁注

实际上,运行 主循环中可以包含更多内容。它还进行了很多优化,以确保它只在需要时 运行ning 避免不断 运行ning cpu 或在没有任何变化时重绘,这会破坏你的电池寿命.这应该足以理解大多数 iOS 开发,除非您开始直接与主 运行 循环交互或创建其他 运行 循环,但这很少需要。