将模型数据指针与 NSWindow 相关联

associate model data pointer with NSWindow

我有一个 MacOS appkit 应用程序,其中包含许多不同的 NSWindows(数百个),它们都是从故事板创建的。

其中许多 NSWindows 都有包含复杂嵌入式 view/view 控制器层次结构的容器视图。

在初始化期间,有必要知道与任何给定 NSWindow 相关联的模型对象,这样它的子视图和控件才能正确初始化。由于任何 NSController 都可以知道它的 NSView,并且任何 NSView 都可以知道它的 NSWindow,因此最好将这些信息与 NSWindow 一起存储。

如果能为 NSWindow 设置一个 "representedObject" 就好了,但与 NSViewController 不同的是,它实际上并没有。

是为每个 NSWindow 情节提要对象创建简单自定义 class(派生自一个小基础 class)的唯一真正解决方案,因此视图层次结构中的 NSViews 和 NSViewControllers 可以获得到我的模型数据(指针)?

澄清:在我们的数百个故事板中,我的 NSWindow 对象很少有自定义 classes 或从 NSWindow 派生的代码。因此,虽然类别对于将 API 添加到 classes 以访问与 NSWindow 关联的模型数据绝对有帮助,但它对 创建 a 属性 或实例变量并在所有这些 NSWindow 故事板中对其进行初始化。

最终我提出了一个简单但糟糕得令人作呕的解决方案,任何人都不应复制:

我们的应用程序不使用 NSDocument,它提供了一种将 NSWindow 对象与 document/model 体系结构相关联的工具。所以我们的目标是让每个 NSController 和 NSView 都能访问初始化视图控件所需的适当的单一文档模型对象。

Apple 工程专家警告我不能依赖视图和子视图的创建和初始化顺序。这使得将数据向下传递到复杂的故事板嵌入式子视图变得棘手且容易出错。

但是 -- 由于所有 UI 都在主线程上,因此 MacOS 上的单个应用程序无法创建、初始化和显示一个情节提要并让另一个情节提要初始化和显示中断该进程(至少不是我们的用户调用的应用程序故事板)。所以简单的解决方案是...

...临时设置具有所需文档模型指针的应用程序级全局变量。那,以及基于堆栈的锁定计数,以确保永远不会违反上述假设。 糟糕的设计高效解决方案.

没有人需要提醒我为什么这不好。但如果有更好的解决方案,它已经逃脱了我的测试。我发现即使是 viewDidLoad 和 viewWillAppear 也不能相信有一个可靠的指针返回它的 NSWindow...

不知道你的申请结构;您将需要一种机制来将模型指针分配给每个人 window。这将需要在某处 添加一些代码。 NSWindow 子类似乎很合适。

在 AppKit MVC 模式中,模型数据通常位于视图和视图控制器之间。尝试将模型与 window 相关联在某种程度上与这种模式作斗争。

话虽这么说; Objective C runtime 确实允许您使用类别向现有 类 添加自定义属性。这是使用关联引用实现的。相关函数是:

objc_setAssociatedObject
objc_getAssociatedObject
objc_removeAssociatedObjects

这篇 article 很好地概述了这种方法的优缺点。