继承NSWindow创建SettingWindow时出现unrecognized selector错误
为什么继承NSWindow时调用
init(contentViewController:)会触发未识别选择器错误? 错误核心原因
你遇到的-[SettingWindow windowWithContentViewController:]: unrecognized selector sent to instance错误,本质是对NSWindow初始化器的误解:
- NSWindow没有
init(contentViewController:)这个实例初始化器——你调用的这个方法,实际上是NSWindow提供的类级便利构造器(对应Objective-C的类方法windowWithContentViewController:),而非实例初始化器。 - 当你在子类的自定义
init()里尝试调用super.init(contentViewController:)时,Swift会将这个调用映射到Objective-C的类方法,但你的子类并没有重写该类方法,导致运行时无法找到对应实现,从而抛出未识别选择器错误。
第二个代码正常运行的原因
第二个代码能正常工作,是因为它遵循了Cocoa类的初始化规则:
- 调用了NSWindow的指定初始化器
init(contentRect:styleMask:backing:defer:)——这是NSWindow类唯一的指定初始化器,所有子类必须通过调用它来完成父类的初始化。 - 之后手动设置
contentViewController,是直接给实例属性赋值,属于合法的实例操作,不会触发任何隐式的类方法调用。
补充说明(Cocoa初始化规则)
对于Cocoa框架中的类,很多看似实例初始化器的方法其实是类便利构造器。子类化这些类时,必须严格调用父类的指定初始化器,而非便利构造器。NSWindow仅拥有init(contentRect:styleMask:backing:defer:)这一个指定初始化器,其他所有初始化方式都是基于它封装的便利构造器。
修正第一个代码的示例
如果想保留类似第一个代码的简洁写法,可以在子类中正确实现初始化逻辑:
import Cocoa final class SettingWindow: NSWindow { static let shared = SettingWindow() private let tabViewController: NSTabViewController private init() { tabViewController = NSTabViewController() tabViewController.tabStyle = .toolbar tabViewController.title = "Setting" // 必须调用父类的指定初始化器 super.init(contentRect: .zero, styleMask: [.titled, .closable, .resizable], backing: .buffered, defer: false) contentViewController = tabViewController } // Cocoa类子类必须实现required初始化器(应对Storyboard/XIB场景) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
内容的提问来源于stack exchange,提问作者yys
相关产品推荐
相关产品推荐

