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

如何在SwiftUI代码中访问macOS AppDelegate的NSPopover属性

如何在SwiftUI代码中关闭AppDelegate里的NSPopover

针对你的需求,这里提供三种可行的实现方式,你可以根据项目架构选择最合适的:

方法一:将AppDelegate作为环境对象传递

利用SwiftUI的环境对象机制,把AppDelegate的实例传递到需要关闭popover的视图中:

  1. 修改ExampleApp的场景配置,在需要的视图中注入AppDelegate实例:
@main
struct ExampleApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var delegate

    var body: some Scene {
        WindowGroup {
            MenuView()
                .environmentObject(self.delegate.authentication)
                .environmentObject(delegate) // 注入AppDelegate
        }
        // 其他场景同理,按需注入
    }
}
  1. 在目标SwiftUI视图中获取AppDelegate并调用关闭方法:
struct SomeView: View {
    @EnvironmentObject var appDelegate: AppDelegate // 获取AppDelegate实例
    // 其他属性...

    func handleFileCheck(url: URL) {
        checkFile(localURL: url, completion: { res, error in
            // 关闭popover
            appDelegate.closePopover()
        })
    }

    var body: some View {
        // 视图内容...
    }
}

方法二:使用通知中心(NotificationCenter)

通过发送通知的方式触发AppDelegate中的关闭逻辑,适合不想直接依赖AppDelegate的场景:

  1. 在AppDelegate中注册通知监听:
    在applicationDidFinishLaunching方法末尾添加:
func applicationDidFinishLaunching(_ notification: Notification) {
    // 原有代码...
    
    // 注册关闭popover的通知监听
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(closePopover),
        name: NSNotification.Name("CloseAppPopover"),
        object: nil
    )
}
  1. 在SwiftUI代码中发送通知:
checkFile(localURL: url, completion: { res, error in
    // 发送通知关闭popover
    NotificationCenter.default.post(
        name: NSNotification.Name("CloseAppPopover"),
        object: nil
    )
})

方法三:使用独立的状态管理类(推荐)

将popover的控制逻辑抽离到单独的ObservableObject类中,更符合SwiftUI的状态管理理念,解耦AppDelegate和视图:

  1. 创建PopoverManager类:
import SwiftUI
import AppKit
import Combine

class PopoverManager: ObservableObject {
    @Published var isPopoverShown = false
    
    func closePopover() {
        isPopoverShown = false
    }
}
  1. 修改AppDelegate,集成PopoverManager:
class AppDelegate: NSObject, NSApplicationDelegate{
    var statusItem: NSStatusItem?
    var popOver = NSPopover()
    var authentication = Authentication()
    let popoverManager = PopoverManager() // 初始化管理器
    private var cancellables = Set<AnyCancellable>() // 用于存储订阅

    func applicationDidFinishLaunching(_ notification: Notification) {
        // 监听popover状态变化,同步控制NSPopover
        popoverManager.$isPopoverShown
            .sink { [weak self] isShown in
                guard let self = self else { return }
                if !isShown && self.popOver.isShown {
                    self.popOver.performClose(nil)
                }
            }
            .store(in: &cancellables)
        
        // 原有代码...
        let menuView = MenuView()
            .environmentObject(authentication)
            .environmentObject(popoverManager) // 注入管理器到视图
        // 原有代码...
    }
    
    // 修改MenuButtonToggle方法,同步状态
    @objc func MenuButtonToggle(sender: AnyObject? = nil){
        if popOver.isShown{
            popOver.performClose(sender)
            popoverManager.isPopoverShown = false
        }
        else{
            if let menuButton = statusItem?.button{
                NSApplication.shared.activate(ignoringOtherApps: true)
                self.popOver.show(relativeTo: menuButton.bounds, of: menuButton, preferredEdge: NSRectEdge.minY)
                popoverManager.isPopoverShown = true
            }
        }
    }
    
    // 原有其他方法...
}
  1. 在SwiftUI视图中使用PopoverManager:
struct SomeView: View {
    @EnvironmentObject var popoverManager: PopoverManager // 获取管理器
    
    func handleFileCheck(url: URL) {
        checkFile(localURL: url, completion: { res, error in
            // 关闭popover
            popoverManager.closePopover()
        })
    }
    
    var body: some View {
        // 视图内容...
    }
}

内容的提问来源于stack exchange,提问作者Nat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 07:05:21