macOS菜单栏图标切换报错:无法强制转换AppDelegate类型
macOS菜单栏图标切换时类型转换报错解决
尝试通过按钮切换macOS菜单栏图标,点击按钮时在代码行let appDelegate = NSApplication.shared.delegate as! AppDelegate出现以下报错:
Could not cast value of type 'SwiftUI.AppDelegate' (0x20dfafd68) to 'MenuBarTest.AppDelegate' (0x10442c580)
主Swift文件代码
@main struct MenuBarTestApp: App { @NSApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { ContentView() } } } class AppDelegate: NSObject, NSApplicationDelegate { var statusItem: NSStatusItem? var popOver = NSPopover() func applicationDidFinishLaunching(_ notification: Notification) { let menuView = MenuBarView() popOver.behavior = .transient popOver.animates = true popOver.contentViewController = NSViewController() popOver.contentViewController?.view = NSHostingView(rootView: menuView) statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) if let MenuButton = statusItem?.button { MenuButton.image = NSImage(named: "settings_bw") MenuButton.image?.size = NSSize(width: 18.0, height: 18.0) MenuButton.action = #selector(MenuButtonToggle) } } func setIcon(colorType:String) { var icon = NSImage(named: "settings_color") if colorType != "color" { icon = NSImage(named: "settings_bw") } statusItem?.button?.image = icon } @objc func MenuButtonToggle(sender: AnyObject) { if popOver.isShown { popOver.performClose(sender) } else { if let MenuButton = statusItem?.button { self.popOver.show(relativeTo: MenuButton.bounds, of: MenuButton, preferredEdge: NSRectEdge.minY) popOver.contentViewController?.view.window?.makeKey() } } } }
MenuBar View代码
struct MenuBarView: View { var body: some View { VStack { Button(action: { let appDelegate = NSApplication.shared.delegate as! AppDelegate appDelegate.setIcon(colorType: "color") }, label: { Text("Change Icon") }) } .frame(width: 150, height: 100) } }
报错原因
使用@NSApplicationDelegateAdaptor时,NSApplication.shared.delegate指向的是SwiftUI内部生成的代理包装类,而非我们自定义的AppDelegate实例,直接强制类型转换必然失败。
解决方法
方法一:通过环境变量传递AppDelegate
- 定义环境键:
private struct AppDelegateKey: EnvironmentKey { static let defaultValue: AppDelegate? = nil } extension EnvironmentValues { var appDelegate: AppDelegate? { get { self[AppDelegateKey.self] } set { self[AppDelegateKey.self] = newValue } } }
- 在创建
MenuBarView时注入环境变量:
修改AppDelegate的applicationDidFinishLaunching方法中创建视图的代码:
let menuView = MenuBarView().environment(\.appDelegate, self)
- 修改
MenuBarView使用环境变量:
struct MenuBarView: View { @Environment(\.appDelegate) private var appDelegate var body: some View { VStack { Button(action: { appDelegate?.setIcon(colorType: "color") }, label: { Text("切换图标") }) } .frame(width: 150, height: 100) } }
方法二:使用静态共享实例
- 在
AppDelegate中添加静态共享属性:
class AppDelegate: NSObject, NSApplicationDelegate { static var shared: AppDelegate! // 原有属性... func applicationDidFinishLaunching(_ notification: Notification) { Self.shared = self // 原有代码... } // 原有方法... }
- 修改
MenuBarView直接调用共享实例:
struct MenuBarView: View { var body: some View { VStack { Button(action: { AppDelegate.shared.setIcon(colorType: "color") }, label: { Text("切换图标") }) } .frame(width: 150, height: 100) } }
内容的提问来源于stack exchange,提问作者Darrell Brogdon
相关产品推荐
相关产品推荐

