SwiftUI 2.0使用NSViewRepresentable移除NSWindow的.titled样式崩溃如何解决
崩溃原因
本次崩溃与canBecomeKey属性无关,核心触发原因是NSWindow的styleMask不能仅配置.fullSizeContentView:该属性属于窗口附加属性,必须搭配.titled这类基础窗口样式使用。你直接清空所有基础样式位的操作会导致AppKit内部访问不存在的窗口结构,触发野指针错误,也就是你遇到的EXC_BAD_ACCESS报错。
修复方案
基础窗口样式修改
保留.titled基础样式,通过属性配置隐藏标题栏相关元素即可,修复后的WindowAccessor代码如下:
struct WindowAccessor: NSViewRepresentable { @Binding var window: NSWindow? func makeNSView(context: Context) -> NSView { let view = NSView() DispatchQueue.main.async { guard let window = view.window else { return } self.window = window // 保留.titled基础样式,额外添加fullSizeContentView window.styleMask.insert(.fullSizeContentView) window.isOpaque = false window.backgroundColor = .clear // 完全隐藏标题栏视觉效果 window.titlebarAppearsTransparent = true window.titleVisibility = .hidden // 隐藏系统默认窗口控制按钮 window.standardWindowButton(.closeButton)?.isHidden = true window.standardWindowButton(.miniaturizeButton)?.isHidden = true window.standardWindowButton(.zoomButton)?.isHidden = true window.isMovableByWindowBackground = true window.backingType = .buffered } return view } func updateNSView(_ nsView: NSView, context: Context) {} }
类Spotlight菜单栏应用适配
针对你要开发无Dock图标、仅菜单栏入口的应用的需求,推荐使用NSApplicationDelegateAdaptor接入自定义AppDelegate来管理状态栏项和窗口,比默认WindowGroup方案更符合交互需求:
- 隐藏Dock图标:在项目Info.plist中新增键
Application is agent (UIElement),值设置为YES - 完整的AppDelegate接入示例:
class AppDelegate: NSObject, NSApplicationDelegate { private var statusItem: NSStatusItem? private let popover = NSPopover() func applicationDidFinishLaunching(_ notification: Notification) { // 配置状态栏项 statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) guard let statusButton = statusItem?.button else { return } statusButton.image = NSImage(systemSymbolName: "magnifyingglass", accessibilityDescription: "搜索") statusButton.action = #selector(togglePopover) // 配置弹出窗口 popover.contentSize = NSSize(width: 600, height: 100) popover.behavior = .transient // 点击外部自动关闭 popover.contentViewController = NSHostingController(rootView: ContentView()) } @objc private func togglePopover() { guard let statusButton = statusItem?.button else { return } popover.isShown ? popover.performClose(nil) : popover.show(relativeTo: statusButton.bounds, of: statusButton, preferredEdge: .minY) } } // SwiftUI 入口适配 @main struct MyApp_App: App { @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { // 移除默认WindowGroup,仅保留偏好设置窗口入口 Settings { // 你的偏好设置页面实现 Text("偏好设置") .frame(width: 400, height: 300) } } }
这样实现的效果和Spotlight完全一致:点击菜单栏图标弹出搜索窗口,点击任意外部区域自动关闭,无Dock图标,没有多余的窗口标题栏。
内容的提问来源于stack exchange,提问作者mousebat
相关产品推荐
相关产品推荐

