You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

macOS菜单栏App启动崩溃:SwiftUI/AppWindowsController.swift:89致命错误求助

解决macOS菜单栏应用SwiftUI/AppWindowsController.swift:89崩溃问题

问题描述

运行macOS菜单栏应用时触发致命错误:
SwiftUI/AppWindowsController.swift:89: Fatal error

开发环境:Xcode 15.2、Swift 5.9.2、最低部署版本macOS 14.2,无论将Info.plist中LSUIElement(对应Application is agent (UI Element))设为YES或NO,应用都会崩溃,怀疑和AppStorage有关。

崩溃原因

  1. 重复绑定AppStorage键:在GiveMeTwentyApp和ContentView中同时声明了@AppStorage(SettingsKeys.showAppInMenuBar),当该值通过ContentView的Toggle修改时,会同时触发App层MenuBarExtra的插入/移除操作,导致Scene结构动态变化,窗口管理逻辑无法处理引发崩溃。
  2. LSUIElement与WindowGroup冲突:当应用以代理模式(LSUIElement=YES)运行时,普通WindowGroup的显示逻辑与菜单栏应用的窗口管理存在冲突,进一步加剧崩溃概率。

解决方案

1. 统一状态管理,避免重复绑定

将所有AppStorage状态提升到App结构体中,通过Binding传递给ContentView,避免重复声明同一个存储键。

2. 条件控制WindowGroup显示

当LSUIElement设为YES时,隐藏普通WindowGroup,避免窗口管理冲突。

修复后的完整代码

App结构体代码

import SwiftUI

@main
struct GiveMeTwentyApp: App {
    @AppStorage(SettingsKeys.showAppInMenuBar) var showAppInMenuBar: Bool = true
    @AppStorage(SettingsKeys.reminderFrequency) var reminderFrequency: Int = 1
    @AppStorage(SettingsKeys.notificationsEnabled) var notificationsEnabled: Bool = true
    @AppStorage(SettingsKeys.runWhenComputerStarts) var runWhenComputerStarts: Bool = true
    @AppStorage(SettingsKeys.popUpMenuMessage) var popUpMenuMessage: String = "Give Me Twenty!"
    
    // 获取LSUIElement配置值
    private var isAgentApp: Bool {
        Bundle.main.object(forInfoDictionaryKey: "LSUIElement") as? Bool ?? false
    }
    
    var body: some Scene {
        #if os(macOS)
        MenuBarExtra(isInserted: $showAppInMenuBar) {
            ContentView(
                reminderFrequency: $reminderFrequency,
                notificationsEnabled: $notificationsEnabled,
                runWhenComputerStarts: $runWhenComputerStarts,
                showAppInMenuBar: $showAppInMenuBar,
                popUpMenuMessage: $popUpMenuMessage
            )
            .navigationTitle("GiveMeTwenty")
        } label: {
            Label("GiveMeTwenty", systemImage: "star")
        }
        .menuBarExtraStyle(.window)
        #endif
        
        // 仅在非代理模式或隐藏菜单栏时显示普通窗口
        if !isAgentApp || !showAppInMenuBar {
            WindowGroup {
                ContentView(
                    reminderFrequency: $reminderFrequency,
                    notificationsEnabled: $notificationsEnabled,
                    runWhenComputerStarts: $runWhenComputerStarts,
                    showAppInMenuBar: $showAppInMenuBar,
                    popUpMenuMessage: $popUpMenuMessage
                )
                .navigationTitle("GiveMeTwenty")
            }
        }
    }
}

ContentView代码

import SwiftUI

struct ContentView: View {
    @Binding var reminderFrequency: Int
    @Binding var notificationsEnabled: Bool
    @Binding var runWhenComputerStarts: Bool
    @Binding var showAppInMenuBar: Bool
    @Binding var popUpMenuMessage: String
    
    private let reminderFrequencyOptions = [1, 2, 3, 4, 5, 6, 7, 8]
    
    var body: some View {
        VStack(alignment: .leading) {
            HStack {
                Picker("Every", selection: $reminderFrequency) {
                    ForEach(reminderFrequencyOptions, id: \.self) {
                        Text($0.description)
                    }
                }
                .frame(width: 80)
                .clipped()
                
                Text("hours take a break.")
                
            }
            .padding()
            
            Toggle(isOn: $notificationsEnabled) {
                Text("Enable notifications")
            }
            .toggleStyle(.checkbox)
            .padding()
            
            Toggle(isOn: $runWhenComputerStarts) {
                Text("Run when computer starts")
            }
            .toggleStyle(.checkbox)
            .padding()
            
            Toggle(isOn: $showAppInMenuBar) {
                Text("Show app in menu bar")
            }
            .toggleStyle(.checkbox)
            .padding()
            
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
        .padding()
    }
}

SettingsKeys代码(保持不变)

import Foundation

enum SettingsKeys {
    static let reminderFrequency = "reminderFrequency"
    static let runWhenComputerStarts = "runWhenComputerStarts"
    static let showAppInMenuBar = "showAppInMenuBar"
    static let popUpMenuMessage = "popUpMenuMessage"
    static let notificationsEnabled = "notificationsEnabled"
}

额外注意事项

  • 测试前建议清除应用的UserDefaults数据(可通过删除容器或重置模拟器解决),避免旧的存储值干扰。
  • 若仍有崩溃,可尝试移除menuBarExtraStyle(.window),改用默认的菜单样式测试,排查窗口样式是否引发问题。

内容的提问来源于stack exchange,提问作者N.K.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:47:08