共享托管对象上下文

Posted

技术标签:

【中文标题】共享托管对象上下文【英文标题】:Sharing Managed Object Context 【发布时间】:2011-12-12 06:48:57 【问题描述】:

我正在编写一个测试程序,它使用具有多个选项卡视图的选项卡控制器。该程序通过 Core Data 下载多个 XML 文件、解析和填充 sqlite 表。 Core Data 变量和函数位于 Xcode 创建代码之后的 App Delegate 文件中。

我首先将 managedObjectContext 变量传递给需要它的每个子视图,因为我在 App Delegate 中对其进行了初始化,例如:

FirstViewController *vc1;
vc1 = [[[FirstViewController alloc] initWithNibName:@"FirstView" bundle:nil] autorelease];
[vc1 setManagedObjectContext:self.managedObjectContext];

但是,我有一个函数 (resetData) 可以删除整个数据存储——删除持久存储文件并将所有核心数据变量(managedObjectContext、managedObjectModel、persistentStore 等)设置为 nil,重新初始化所有内容。这样程序就可以从头开始并从网络重新下载所有数据。发生这种情况时,子视图现在指向旧的 managedObjectContext。

在所有子视图中更新 managedObjectContext 变量的最佳方法是什么?从 resetData 函数手动更新子视图的 managedObjectContext 变量?使用 NSNotificationCenter 向所有视图发送通知?完全删除并重新初始化所有持久存储文件是否过大?

我目前已将这个仅引用回 App Delegate 的 getter 放在所有需要引用 MOC 的类中:

- (NSManagedObjectContext *)managedObjectContext 
    MyAppDelegate* ad = (MyAppAppDelegate*)[[UIApplication sharedApplication] delegate];
    return [ad managedObjectContext];

我对 Cocoa / ios 设计模式非常陌生,我正在尝试找出最合适的方法来做这些事情!我现在得到的东西有效,但我想知道是否有看不见的陷阱或未来的问题?谢谢!

【问题讨论】:

“完全删除并重新初始化所有持久存储文件是否过大?”大概。您可以删除所有对象吗? @jrturton 删除所有对象绝对值得一试。但是如果有很多,它可能会很慢。 CoreData 不是数据库。 @tonklon - 当然可以。但是从这个问题我们不知道有多少物体。你的回答非常好。重新创建 VC 堆栈是要走的路 我走现在这条路的原因——把它全部扔掉然后重新开始——是因为删除对象似乎相当慢。 【参考方案1】:

恕我直言,将 managedObjectContext 传递到 ViewControllers 是一种很好的做法。它使测试更容易并创建更好的可重用 ViewController。

实现所需结果的一种方法是简单地从存储中删除所有对象,同时保持 CoreData 堆栈不变。所有视图控制器都将简单地使用与以前相同的上下文,但它不再包含对象。但这可能会很慢,具体取决于对象的数量。

删除所有对象的最快和最有效的方法确实是删除存储文件。 NSManagedObjectContext 为持久存储协调器提供了一个设置器。您是否尝试过使用新文件创建新的 storeCoordinator,将其设置为 MOC 的 storeCoordinator,然后释放旧的 coordinator 并删除旧文件?在这种情况下,您可能需要发送通知,因为所有 ViewController 都必须释放它们可能保留的 managedObjects。

我刚刚想到的另一个想法是,我之前使用过的方法是完全删除完整的 viewController 堆栈,然后使用新的 managedObjectContext 重新创建它。您可以在后台轻松下载、解析并将新数据保存到它自己单独的 managedObjectContext(具有自己的 persistentStoreController 和自己的商店)中。完成后,从窗口中删除所有控制器,并显示与控制器的跟踪。然后移动新的 store 文件覆盖旧的,并像以前一样重新创建 viewController 堆栈。虽然这听起来像是一项昂贵的操作,但事实并非如此。在我的情况下,这个开关在 UI 中甚至都不明显。与保留 viewController 相比的优势在于,旧的 managedObjects 仍然潜伏在某个地方的可能性要小得多,因此需要额外编辑的代码更少。如果您的 viewControllers 已经按照 Apple 推荐的方式进行了设置,那么这个开关很有可能“正常工作”。

【讨论】:

关于 viewController 堆栈的有趣想法...我得考虑一下!谢谢【参考方案2】:

没有最好的方法,只有好的实现。您最后一个始终通过应用程序委托访问上下文的解决方案很好。请记住,在这种情况下,如果实例变量是合成的,则不能使用它。

我想您的对象需要知道持久数据何时被重置,因此它们正在使用新的上下文。您可以使用实例变量来检查它:

@synthesize managedObjectContext = moc_ ;

然后就可以测试了:

- (NSManagedObjectContext *)managedObjectContext 
    MyAppDelegate* ad = (MyAppAppDelegate*)[[UIApplication sharedApplication] delegate];

    if(moc_ != [ad managedObjectContext]) 
          // NEW CONTEXT. DO ANYTHING NEEDED TO RESET OBJECT
    

    // Use property to change value to ensure set rules (retain for example).
    [self setManagedObjectContext:[ad managedObjectContext]];

    return moc_;

【讨论】:

【参考方案3】:

在使用CoreData 时,我通常使用Singleton 模式

【讨论】:

以上是关于共享托管对象上下文的主要内容,如果未能解决你的问题,请参考以下文章

选项卡栏应用程序更新实体中的共享托管对象上下文不会传播到其他选项卡

当每个线程可以处理与其他线程中的数据无关的数据时,是不是可以在线程之间重用一个共享托管对象上下文?

其他线程可以间接访问在自己的线程中运行的托管对象上下文吗?

当一个托管对象在 moc A 中被删除时,它还会出现在 moc B 中吗?

共享对象和线程

批量更新后更新托管对象上下文中的托管对象