将永远不会更改的对象传递给 NSWindowController 的正确方法是什么?

What's the correct way to pass an object that will never change to an NSWindowController?

我有一个显示 table 的 NSWindowController 并使用另一个控制器作为 NSTableView 的数据源和委托。第二个控制器显示来自对象的信息,该对象由 NSWindowController 传入。该控制器依次将对象设置为 AppDelegate 的 属性。它看起来像这样:

class SomeWindowController: NSWindowController {
    var relevantThing: Thing!
    var someTableController: SomeTableController!
    @IBOutlet weak var someTable: NSTableView!

    override func windowDidLoad() {
        someTableController = SomeTableController(thing: relevantThing)
        someTable.dataSource = someTableController
        someTable.delegate = someTableController
    }
}

AppDelegate 然后我会做类似

func applicationDidFinishLaunching(_ aNotification: Notification) {
    relevantThing = Thing()
    someWindowController = SomeWindowController()
    someWindowController.relevantThing = relevantThing
    someWindowController.showWindow(nil)
}

这是一个合理的方法吗?我觉得 SomeWindowController 中使用的隐式解包选项可能是错误的形式。此外,relevantThing 不允许在我的情况下更改,所以我觉得 let 会更正确。也许 relevantThing 应该保持不变并通过初始化器传入?还是会破坏 init?(coder: NSCoder) 初始值设定项?

我非常感谢任何建议,因为我正试图了解在 Swift 中做事的正确方法。

几件事:

您在代码中创建 window 控制器而不是从 storyboard/xib 加载它有什么原因吗?

一般来说,更好的做法是将所有与视图相关的 'controller' 放在 NSViewController 中,并仅将 NSWindowController 用于与 [=53= 相关的内容] 本身(例如工具栏、window 管理等)。

与 iOS 类似,NSViewController 现在已集成到 window/view 生命周期和响应链中。对于许多 windows 你甚至不需要 subclass NSWindowController.

XCode 的应用程序项目模板使用 window、主视图及其控制器创建故事板。这是一个很好的起点。

NSWindowController 有一个 contentViewController 属性 设置为主要内容视图的 NSViewController(从故事板加载时)。通常,您的视图控制器不需要单独的视图控制器 属性。

我认为通常情况下,您希望尽量减少从外部代码修改您的控制器并使它们尽可能独立。这使它们更易测试table并且可重复使用。

如果您的 Thing 实例对于整个应用程序是全局的(从您的代码中可以看出),您可能需要考虑将其作为单例实例添加到 Thing class 并从 NSViewController 中检索它(例如在 viewDidLoad() 中)

如果您将 controllers/views 放在故事板中,您可以在那里连接 table 的 datasource/delegate。如果这是您的主要 window,它可以在应用程序启动时自动加载并显示它。但无论如何,请将您的 NSViewController/View 布线放在视图控制器中。

如果您想将主 NSViewController 之间的逻辑分离到处理视图特定部分的更专业的视图控制器中,您可以在 Interface Builder 中使用 NSContainerView 添加额外的视图控制器来处理特定视图.