使用 NSArrayController 管理有序的核心数据关系

Posted

技术标签:

【中文标题】使用 NSArrayController 管理有序的核心数据关系【英文标题】:Managing an Ordered Core Data Relationship Using NSArrayController 【发布时间】:2013-12-21 12:33:54 【问题描述】:

所有那些“NSOrderedSet 是后来添加的,因此不必与其他组件配合得很好”的错误让我抓狂……

(https://twitter.com/kubanekl/status/413447039855640576)

我有两个托管对象和它们之间的有序 1:N 关系,它由 NSOrderedSet 的实例(或更准确地说是子类)支持。我想使用NSArrayController 管理这种关系,以便从它提供的功能(选择管理、内容绑定、与NSTableView 等视图的绑定)中获利。

由于NSOrderedSet 不是NSSet 的子类,NSArrayControllercontentSet 绑定不适用于该关系。我找到了following thread 并尝试实施那里提到的建议。

第一个建议是使用contentArray 绑定和值转换器将有序集动态转换为数组。此解决方案的问题是每次进行更改时都会重新分配内容,这不是我想要的。

上述线程中提供的第二个建议是使用contentArray 绑定并将@array 运算符应用于模型键路径。我已经尝试过了,但是通过NSArrayController 添加/删除对象时,底层关系根本没有触及

我发现的另一个选项是使用带有contentSet 绑定的排序描述符。这将需要使关系无序以使contentSet 绑定工作并引入一个专门用于管理订单的新属性。这还需要自定义排序机制来实现,并且会破坏模型。老实说,我想避免这种解决方案。

我的问题很明确:有没有办法使用NSArrayController 来管理有序的核心数据关系?如果是这样,哪种方法能尽可能减少疼痛?

【问题讨论】:

【参考方案1】:

NSArrayController 不支持有序关系确实很遗憾。作为绑定技术的敏锐观察者,我发现苹果似乎已经“放弃”了它而没有说什么是次优的。 Apple 在绑定方面引入的最后一个值得注意的变化是 NSTreeController 错误修复。我相信 10.6/10.7 就是这样。看来苹果不想再碰绑定技术了。我不知道为什么,因为绑定有时真的很棒。它们可以是“90% 的解决方案”。在原型制作期间,这很好。我在有意义的地方使用绑定,并且让 NSArrayController 支持有序关系会很棒。

已经提到的大多数解决方案都不是真正的解决方案。但这取决于。以下是需要考虑的事情:

    如果您计划支持 iCloud,那么无论如何您都不应该/不能使用有序关系,因为 iCloud 上的 Core Data 不支持它们。 由于有序关系是相当新的,而且对有序对象集合的需求早在它们之前就已经存在,因此在 Core Data 中必须有一种方法来模拟有序关系。您已经指出 99.9% 的 Core Data 饮食世界在有序关系可用之前所做的事情:按附加属性排序。您已经指出这会弄乱模型,但我不同意:确实,您必须向模型添加一个附加属性,该属性不一定“代表”真实的模型数据。但是你计划在你的模型中有多少有序的关系呢?通常每个应用程序没有那么多。尽管感觉有点脏,但很多人在 Core Data 的至少三个主要版本(10.4、10.5 和 10.6)中已经这样做了。即使在今天,这个解决方案也用于向后兼容或者如果你想使用 iCloud。这是一个“务实”的解决方案。不是很好,但很务实。也请不要:即使您使用有序关系,对象的顺序也必须存储在某个地方。如果您使用的是 SQLite 存储,那么具有有序关系会导致 NSSQLiteStore 为您创建一个附加列。该列的名称为:Z_FOK_$RELATIONSHIPNAME。因此,通过使用有序关系,无论如何您只是在做一些在幕后为您完成的事情。这意味着从纯技术角度来看,如果您使用有序关系或附加属性,这并不重要。潜在的技术问题保持不变。有序的关系并不神奇。 如果您打算使用“附加属性”解决方案,请注意您必须大量调整此属性的值:每次用户通过拖放更改顺序时,您都必须修改属性。这看起来很浪费,但实际上并非如此。更糟糕的情况是:用户将第 0 行的对象与可能的最后一行的对象交换只会导致 2 次属性更改。表示可以通过拖放在表格视图中进行的任何更改所需的更改的简单解决方案的复杂性是 O(n),其中 n 是选定行的数量。这真的没那么糟糕,因为用户通常不会一次重新排序 10000000 行,即使这样,也有更智能的算法,实现起来并不难。 如果您正在寻找最干净的解决方案,您应该继承 NSArrayController 并自己添加一个“orderedContentSet”绑定。您可以通过阅读 Cocoa Bindings Programming 主题指南了解如何做到这一点。该指南包含一个示例:https://developer.apple.com/library/mac/documentation/cocoa/conceptual/CocoaBindings/Concepts/HowDoBindingsWork.html(清单 2)。这样做的坏处是您将 NSArrayController 子类化,这通常是不可行的。许多人倾向于继承 NSArrayController 的原因并不能证明继承它是合理的。但是,在这种情况下,如果您想使用最干净的解决方案,则继承 NSArrayController 是合理的。 对于 3. 有一些通用的解决方案可以为您做很多事情。不要使用它们。

【讨论】:

以上是关于使用 NSArrayController 管理有序的核心数据关系的主要内容,如果未能解决你的问题,请参考以下文章

NSArrayController 的奇怪行为

如何使用 NSArraycontroller 在可可上创建 NSFetchedresultController?

两个 NSArrayController 和一个关系(CoreData)

在没有 NSFetchedResultsController 或 NSArrayController 的情况下使用 AFIncrementalStore

NSTableView 绑定到 NSArrayController

如何将 NSArray 和 NSArrayController 与 Core Data 一起使用?