通过非核心数据对象的绑定访问核心数据对象的属性
Posted
技术标签:
【中文标题】通过非核心数据对象的绑定访问核心数据对象的属性【英文标题】:Accessing properties of Core Data objects via bindings from non-Core Data objects 【发布时间】:2010-08-27 08:45:42 【问题描述】:我有一组由另一个应用程序创建并以 XML 格式存储在磁盘上的数据。由于这些数据是由这个其他应用程序管理的,我不想费心将这些数据加载到核心数据存储中,原因有两个:1)这将是相同数据的冗余存储,2)我必须经常更新我自己的 Core Data 存储以匹配其他应用程序生成的 XML 文件中的更新。
但是,我在自己的应用程序中创建的数据需要与来自其他应用程序的 XML 数据相关联,我想将在自己的应用程序中创建的数据保存到磁盘。
为此,来自其他应用程序的 XML 数据具有与存储在 XML 文件中的每个对象相关联的持久唯一 ID。我将这些唯一 ID 存储在我自己的 Core Data 存储中。每次启动我的应用程序时,我都会加载其他应用程序创建的 XML 数据,然后我可以通过 Core Data 访问我自己的应用程序中的相应数据,方法是发出对匹配唯一 ID 的托管对象的获取请求。
OtherAppObjects 表示从 XML 数据加载的项目。除了 uniqueID 之外,它们还有自己独特的属性。这些 OtherAppObjects 由 NSArrayController 控制。然后我有从核心数据存储加载的 MyManagedObjects,除了唯一 ID 之外,它们还具有不同的唯一属性。
我有一个表格视图,它需要显示来自 OtherAppObjects 和 MyManagedObjects 的属性,因此我希望能够通过来自 OtherAppObjects 的绑定来访问和设置 MyManagedObjects 的属性。因此,我想我可以创建 OtherAppObjects 的对应 MyManagedObject 属性,然后我就可以通过绑定访问 MyManagedObject 的 Core Data 属性。
例如,如果我想在表格视图中显示 OtherAppObjects 的属性“foo”和 MyManagedObjects 的“bar”,我可以简单地将一个表格列绑定到 NSArrayController,模型键路径为“foo” ,并将第二个表列绑定到“correspondingMyManagedObject.bar”的模型键路径。
这在不处理多个线程或传递单个托管对象上下文时有效。但由于“强烈反对”,我想尝试通过传递单个持久存储协调器来以正确的方式执行此操作,但创建单独的托管对象上下文。
但是,这会崩溃。问题是当table view试图访问bar属性时,需要先访问对应的MyManagedObject属性。因此,OtherAppObject 尽职尽责地创建一个新的托管对象上下文和一个具有适当唯一 ID 的相应获取请求,并返回托管对象。但是这样做会释放托管对象上下文,现在托管对象不再有效,因此表格视图无法访问 bar 属性!
我只看到了两种解决方法,我想验证没有其他更简单的方法可以做到这一点:
将 XML 数据中的对象加载到我自己的核心数据存储中。从本质上讲,从 OtherAppObjects 创建 ManagedOtherAppObjects,与 MyManagedObjects 有关系,然后通过绑定访问将是非常好的。但是,这意味着磁盘上存在相同数据的冗余存储,并且我每次启动应用程序时都必须重新创建 ManagedOtherAppObjects(因为 XML 文件更新相当频繁)。 p>
在 OtherAppObject 类上创建自定义设置器/获取器。因此,例如,我将在 OtherAppObject 中创建 -(NSValue *)bar
和 -(void)setBar:(NSValue *)newValue
方法。然后,我不将表视图列绑定到OtherAppObjects 的键值路径“correspondingMyManagedObject.bar”,而是将其绑定到OtherAppObjects 的键路径“bar”。这些方法将能够获取相应的 MyManagedObject 并在托管对象上下文中检索或设置值,然后返回正确的值。
第二种方法并不是特别吸引人,因为我必须为 MyManagedObject 的每个属性创建两个自定义方法(和用于 other 托管对象的属性与哪个 MyManagedObject 有关系)。
我想我可以创建通用方法 -(NSValue *)retrieveCoreDataPropertyUsingKeyPath:(NSString *)keyPath
和 -(void)setCoreDataProperty:(NSValue *)newValue usingKeyPath:(NSString *)keyPath
,但我仍然需要为每个单独的属性创建 shell setter/getter。
[更新:嗯,也许我可以覆盖valueForKeyPath:
和setValue:forKeyPath:
,然后一切都会正常吗?]
这是正确的,还是我遗漏了什么?
【问题讨论】:
【参考方案1】:选项 #1 的一个变体可能值得一试,即进行设置,以便您拥有一个持久存储协调器,将对象在两个单独的持久存储之间拆分。您将保持 MyManagedObjects (MMO) 相同,分别存储在磁盘上,但是 OtherAppObjects (OAO) 可以由磁盘上的一些临时存储支持(例如,在 ~/Library/Caches 或其他地方)或仅由一个 in-内存存储。
启动后,您将创建自己的 PSC 并添加包含 MMO 的商店。然后,您将向 PSC 添加第二个存储(使用 -[NSPersistentStoreCoordinator addPersistentStoreWithType:configuration:URL:options:error:]
),读取 XML 文件并创建所有 OAO,并使用 -[NSManagedObjectContext assignObject:toPersistentStore:]
将这些对象与该存储关联。
Core Data 不允许直接对不同商店中的对象之间的关系进行建模,但您仍然可以通过唯一 ID 进行查找,就像现在将 MMO 与 OAO 关联起来一样。不同之处在于 OAO 可以简单地使用自己的托管对象上下文来获取 MMO,因此您可以确定 MMO 至少会像 OAO 一样存在。
然后,当您退出应用程序时,您可以删除 ~/Library/Caches 中的临时存储,或者如果使用内存存储,则让它消失在以太中,将其他存储留给 MMO完好无损。
【讨论】:
这是一个有趣的想法。我尝试实施它。它像宣传的那样工作,有一个非常大的缺点:性能是不可接受的。在不同存储中保持对托管对象的引用的唯一方法似乎是通过获取请求。所以现在,当我想通过 OAO(它们本身现在是托管对象)访问 MMO 的属性时,我会通过 OAO 的“correspondingMyManagedObject”属性,这只是一个获取请求。从表视图生成数千个这样的 fetch 请求会导致应用程序启动等待两分钟,而之前是 2 秒 嗯,我突然想到我可以通过 objectID 存储对对象的引用,而不需要获取请求......这个想法可能还有效。 如果您使用 objectID,请注意临时 ID,并确保只保存永久 ID。以上是关于通过非核心数据对象的绑定访问核心数据对象的属性的主要内容,如果未能解决你的问题,请参考以下文章