How can I reliably get the final restored window size on macOS when onAppear / viewDidAppear fires too early?

I’m running into a macOS window restoration behavior issue where viewDidAppear (AppKit) or onAppear (SwiftUI) fires before the window’s final restored size is applied.

AppKit example

class MyViewController: NSViewController {
    override func viewDidLayout() {
        print("viewDidLayout: \(view.bounds.size)")
    }
    override func viewDidAppear() {
        print("viewDidAppear: \(view.bounds.size)")
    }
}

Logs on launch:

viewDidAppear: (480.0, 270.0)
viewDidLayout: (480.0, 270.0)
viewDidLayout: (556.0, 476.0)
viewDidLayout: (556.0, 476.0)

The correct restored size is (556.0, 476.0), but viewDidAppear initially reports the old default size (480.0, 270.0).


SwiftUI equivalent

struct MyView: View {
    var body: some View {
        GeometryReader { geo in
            VStack {}
                .onAppear {
                    print("onAppear: \(geo.size)")
                }
                .onChange(of: geo.size) {
                    print("onChange: \(geo.size)")
                }
        }
    }
}

Logs on launch:

onAppear: (900.0, 450.0)
onChange: (680.0, 658.0)

Problem

I need to run some setup code:

  • Only once
  • After the view/window has its correct restored size
  • Without rerunning on every layout or geometry change

Question

What is the proper macOS-native way to perform one-time startup logic only after the final restored window size is available?

Is there a recommended lifecycle hook or pattern for this?

Also, is it expected behavior that onAppear / viewDidAppear reports the pre-restoration size, or is it a bug?

didAppear just means the view is loaded, not initialised.

I once had a similar issue that I worked around as follows:

  • Declared a firstAppearance property initially set to true
  • In viewDidLayout, set to false
  • run the setup code only if firstAppearance is true.

Another option could be to run the setup code after a small delay (e.g. 0.2s) so that the size had time to be set.

Hope that helps.

Never use the comment feature to reply. It hides your reply both from people and the forum's "read/updated" status.

Unfortunately, there is no possible solution here. This is one of my long-standing pet peeves. What you ask is flat-out impossible.

At no point in the auto-layout system can you ever know the "final" layout. In fact, there is no "final" layout. In theory, layouts can always be modified or ambiguous.

Your only option is to rethink what you're trying to do. If you need to take some action on layout, then add it to the layout method, and don't disturb the existing layout. Otherwise, if you need to pre-calculate some value, you'd probably be better off making it a dynamic property that gets calculated as needed.

How can I reliably get the final restored window size on macOS when onAppear / viewDidAppear fires too early?
 
 
Q