如何在SwiftUI代码中访问macOS AppDelegate的NSPopover属性
如何在SwiftUI代码中关闭AppDelegate里的NSPopover
针对你的需求,这里提供三种可行的实现方式,你可以根据项目架构选择最合适的:
方法一:将AppDelegate作为环境对象传递
利用SwiftUI的环境对象机制,把AppDelegate的实例传递到需要关闭popover的视图中:
- 修改ExampleApp的场景配置,在需要的视图中注入AppDelegate实例:
@main struct ExampleApp: App { @NSApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { MenuView() .environmentObject(self.delegate.authentication) .environmentObject(delegate) // 注入AppDelegate } // 其他场景同理,按需注入 } }
- 在目标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的场景:
- 在AppDelegate中注册通知监听:
在applicationDidFinishLaunching方法末尾添加:
func applicationDidFinishLaunching(_ notification: Notification) { // 原有代码... // 注册关闭popover的通知监听 NotificationCenter.default.addObserver( self, selector: #selector(closePopover), name: NSNotification.Name("CloseAppPopover"), object: nil ) }
- 在SwiftUI代码中发送通知:
checkFile(localURL: url, completion: { res, error in // 发送通知关闭popover NotificationCenter.default.post( name: NSNotification.Name("CloseAppPopover"), object: nil ) })
方法三:使用独立的状态管理类(推荐)
将popover的控制逻辑抽离到单独的ObservableObject类中,更符合SwiftUI的状态管理理念,解耦AppDelegate和视图:
- 创建PopoverManager类:
import SwiftUI import AppKit import Combine class PopoverManager: ObservableObject { @Published var isPopoverShown = false func closePopover() { isPopoverShown = false } }
- 修改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 } } } // 原有其他方法... }
- 在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
相关产品推荐
相关产品推荐

