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?