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

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()
            }
        }
    }
}
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

  1. 定义环境键:
private struct AppDelegateKey: EnvironmentKey {
    static let defaultValue: AppDelegate? = nil
}

extension EnvironmentValues {
    var appDelegate: AppDelegate? {
        get { self[AppDelegateKey.self] }
        set { self[AppDelegateKey.self] = newValue }
    }
}
  1. 在创建MenuBarView时注入环境变量:
    修改AppDelegate的applicationDidFinishLaunching方法中创建视图的代码:
let menuView = MenuBarView().environment(\.appDelegate, self)
  1. 修改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)
    }
}

方法二:使用静态共享实例

  1. 在AppDelegate中添加静态共享属性:
class AppDelegate: NSObject, NSApplicationDelegate {
    static var shared: AppDelegate!
    // 原有属性...
    
    func applicationDidFinishLaunching(_ notification: Notification) {
        Self.shared = self
        // 原有代码...
    }
    // 原有方法...
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 16:45:25