Cocoa macOS应用窗口创建:两种实现方案该如何选择?
我在为Cocoa macOS应用创建所需窗口时感到困惑,看到两种不同的实现方案:
方案一代码
import Cocoa import SwiftUI class ViewController: NSViewController { override func viewWillAppear() { self.view = NSHostingView(rootView: ContentView()) self.view.window?.makeKeyAndOrderFront(nil) self.view.window?.standardWindowButton(NSWindow.ButtonType.zoomButton)?.isHidden = true self.view.window?.standardWindowButton(NSWindow.ButtonType.miniaturizeButton)?.isHidden = true self.view.window?.standardWindowButton(NSWindow.ButtonType.closeButton)?.isHidden = true } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } override var representedObject: Any? { didSet { // Update the view, if already loaded. } } }
方案二代码
@main class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application let window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 300, height: 300), styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], backing: .buffered, defer: false) window.center() window.setFrameAutosaveName("Main Window") window.contentView = NSHostingView(rootView: ContentView()) window.makeKeyAndOrderFront(nil) window.standardWindowButton(NSWindow.ButtonType.zoomButton)?.isHidden = true window.standardWindowButton(NSWindow.ButtonType.miniaturizeButton)?.isHidden = true window.standardWindowButton(NSWindow.ButtonType.closeButton)?.isHidden = true } func applicationWillTerminate(_ aNotification: Notification) { // Insert code here to tear down your application } func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { return true } }
建议优先选择方案二,原因如下:
窗口控制权更直接
方案二中直接创建并配置NSWindow实例,全程拥有窗口的完整控制权,不需要依赖view.window?这种可选链调用,避免因窗口未初始化导致的空值问题。方案一中在viewWillAppear里修改窗口属性,此时窗口可能还未完全绑定到视图,存在调用失效的风险。架构职责更清晰
方案二遵循Cocoa应用传统架构:AppDelegate负责应用生命周期和窗口初始化,ViewController专注于视图逻辑。方案一把窗口配置逻辑放在ViewController里,混淆了视图控制器和窗口管理的职责,不符合单一职责原则。初始化时机更可靠
applicationDidFinishLaunching是应用启动完成后的标准回调,此时应用环境已经完全就绪,适合做窗口初始化。而viewWillAppear可能会被多次调用(比如视图切换时),方案一中的代码会重复执行self.view = NSHostingView(...),导致不必要的视图重建和资源浪费。可扩展性更强
如果后续需要添加多窗口管理、窗口状态保存等功能,方案二的结构更容易扩展。直接持有窗口实例的引用,方便后续对窗口进行各种操作;而方案一中要获取窗口实例只能通过view.window,灵活性不足。
如果你的应用非常简单,只有单个视图且不需要复杂的窗口管理,方案一也能勉强运行,但从长期维护和架构规范来看,方案二是更稳妥的选择。
内容的提问来源于stack exchange,提问作者swiftPunk

