加载时设置窗口高度:最大化失效及弱引用警告问题排查
问题修复方案
1. 解决代理被立即释放的警告
NSWindow的delegate是弱引用属性,你之前直接创建临时WindowController实例赋值,因为没有强引用持有它,系统会立刻回收这个实例,所以才会出现警告。必须把WindowController实例通过强引用存起来,比如在视图里用@StateObject。
2. 让窗口尺寸设置生效
你之前对visibleFrame的处理多此一举了——NSScreen.main?.visibleFrame返回的本来就是排除了菜单栏和Dock的屏幕可用区域,不需要再手动调整高度。另外得让窗口控制器真正关联到SwiftUI的窗口,不能随便创建临时实例瞎赋值。
完整修正代码
import AppKit import SwiftUI @main struct demoApp: App { var body: some Scene { WindowGroup ("Demo") { ContentView() } } } class WindowController: NSWindowController, NSWindowDelegate { override func windowDidLoad() { super.windowDidLoad() guard let screenFrame = NSScreen.main?.visibleFrame else { return } // visibleFrame已经是去掉菜单栏和Dock的可用区域,直接用它设窗口大小 window?.setFrame(screenFrame, display: true, animate: false) window?.delegate = self } // 如果要限制窗口调整大小时的最大高度,保留这个方法(按需调整) func windowWillResize(_ sender: NSWindow, to frameSize: NSSize) -> NSSize { guard let screenFrame = NSScreen.main?.visibleFrame else { return frameSize } let maxHeight = screenFrame.height return NSSize(width: frameSize.width, height: min(frameSize.height, maxHeight)) } } struct ContentView: View { // 用@StateObject强持有WindowController实例,防止被系统回收 @StateObject private var windowController = WindowController() var body: some View { Text("Hello, World!") .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.blue) .edgesIgnoringSafeArea(.all) .toolbar { ToolbarItem(placement: .principal) { Text("Title") .font(.headline) } } // 嵌入WindowAccessor,把SwiftUI的窗口和我们的控制器绑定 .background(WindowAccessor(windowController: windowController)) } } struct WindowAccessor: NSViewRepresentable { let windowController: WindowController func makeNSView(context: Context) -> NSView { let view = NSView() DispatchQueue.main.async { if let window = view.window { // 把窗口交给已持有的控制器管理 windowController.window = window windowController.windowDidLoad() } } return view } func updateNSView(_ nsView: NSView, context: Context) {} }
关键修改说明
- 用
@StateObject在ContentView里持有WindowController实例,确保系统不会随便释放它,彻底解决代理被立即回收的警告。 - 修正窗口尺寸计算:直接用
visibleFrame设置窗口,它已经自动排除了菜单栏和Dock的占用,之前手动调整高度的操作反而导致设置失效。 - 通过
WindowAccessor把SwiftUI的窗口和我们持有的控制器绑定,让控制器能真正控制窗口的行为。 - 删除了
onAppear里那种临时创建控制器赋值的错误代码,那是导致代理警告的根源。
改完之后,窗口每次启动都会自动占满可用屏幕区域,两个问题都能解决。
内容的提问来源于stack exchange,提问作者PrettyGirl
相关产品推荐
相关产品推荐

