Search code examples
iosswiftuikit

Isn't layoutSubviews supposed to get called once per frame only?


I thought that view.layoutSubviews() gets called once per frame to avoid computing the layout too many times. That's the whole reason for the existence of view.setNeedsLayout(). Such that you may call view.setNeedsLayout() many times, including many times per frame, but it only gets computed once. That's why you also have a second method, view.layoutIfNeeded() which computes the layout immediately.

This is not what seems to happen here:

class MyViewController: UIViewController {

var time = Date().timeIntervalSince1970

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = .cyan


    Timer.scheduledTimer(withTimeInterval: 0.001, repeats: true) { (timer) in
        self.view.setNeedsLayout()
        print("hello")
    }

}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let newDate = Date().timeIntervalSince1970
    print("Layout called at time: \(newDate - time)")
    time = newDate
}

}

What happens here is "Layout called at time..." get called at 0.001 intervals.


Solution

  • It's not once per frame, it's once per iteration of the run-loop. Since your app isn't really doing anything, this will be about as fast as your interval.