【发布时间】:2010-11-19 01:06:00
【问题描述】:
在 iPhone Core Data Template 中,Apple 将 Core Data Stack 放置在 App Delegate 中。
然而,我最初的想法是将此代码移到它自己的类中,该类的职责是处理核心数据堆栈的管理。
您通常将此功能封装在其自己的类中还是将其保留在 App Delegate 中?
【问题讨论】:
标签: iphone cocoa cocoa-touch core-data
在 iPhone Core Data Template 中,Apple 将 Core Data Stack 放置在 App Delegate 中。
然而,我最初的想法是将此代码移到它自己的类中,该类的职责是处理核心数据堆栈的管理。
您通常将此功能封装在其自己的类中还是将其保留在 App Delegate 中?
【问题讨论】:
标签: iphone cocoa cocoa-touch core-data
总结:无需创建单例来管理Core Data栈;确实这样做可能会适得其反。
Core Data 堆栈恰好是由应用程序委托创建的。然而,重要的是,正如所有示例所示,堆栈(主要是托管对象上下文)不直接从堆栈中检索 (*)。相反,上下文被传递给第一个视图控制器,并从它们在上下文或托管对象中从一个视图控制器传递到下一个视图控制器(如Accessing the Core Data Stack 中所述)。这遵循 iPhone 所有应用程序的基本模式:您将数据或模型控制器从一个视图控制器传递到下一个视图控制器。
这里描述的单例的典型作用是作为模型控制器。使用 Core Data,托管对象上下文已经是一个模型控制器。如果需要,它还使您能够访问堆栈的其他部分。此外,在某些情况下(如文档中所述),您可能希望使用不同的上下文来执行一组离散的操作。因此,视图控制器的适当货币单位通常是托管对象上下文,否则是托管对象。使用和传递管理堆栈(并从中检索上下文)的单例对象通常最多会引入不必要的间接级别,最坏的情况会引入不必要的应用程序僵化。
(*) 没有示例使用以下方法检索上下文:
[[UIApplication delegate] managedObjectContext];
【讨论】:
我有一个单例类,我让它来管理我的核心数据,我不会把它留在应用程序委托上。我宁愿不使用我可能需要的方法来混淆应用程序委托类,例如获取某些对象等
【讨论】:
我将核心数据逻辑留在 App 委托中,原因如下:
1) 我认为将这段代码移到其他类中没有任何真正的优势:委托的概念完全由 App 委托处理的核心数据逻辑实现,因为核心数据模型实际上是你的申请;
2) 在我见过的所有示例代码中,包括 Apple 示例,核心数据都是由 App 委托处理的;
3) 即使在 Core Data 书籍中,让 App 委托处理与核心数据相关的代码也是常见的做法;
4) 就我个人而言,我认为核心数据的临时类实际上并没有提高可读性或其他任何东西,但这是个人喜好问题,我不会在这里争论哪种方法是最好的。对我来说,保持功能的同时保持简单很重要。
【讨论】:
就您而言,我会问自己的问题是“Core Data 堆栈‘属于’谁?”数据本身真的是应用程序的一部分,不是吗? (Mac 上的 C.F. Core Data,您可能有一个应用程序能够同时处理多个文档,因此 Core Data 堆栈属于每个文档。)
在任何 Cocoa/Cocoa Touch 应用程序中,App Delegate 通常是自定义应用程序行为的首选方式,因此这是 Core Data 堆栈的自然位置。
现在,我怀疑你遇到的问题是,不断地写这样的东西感觉不对:
NSManagedObjectContext *context = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
在这些情况下,我通常会写这样的函数(而不是方法):
NSManagedObjectContext *UIAppManagedObjectContext() {
return [*(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
我为NSPersistentStoreCoordinator 和NSManagedObjectModel 编写了一个类似的函数。我将所有这些都放在 App Delegate 的 .h/.m 文件中,因为这些也是应用程序级对象。
【讨论】:
我将在新答案中列出这一点。 (我已经放弃了我以前的 FJSCoreDataStack 课程来支持这个)
我处理这个问题的新方法是在 NSManagedObjectContext 上使用一个类别。我添加了以下类方法:
+ (NSManagedObjectContext *)defaultManagedObjectContext;
+ (NSManagedObjectContext *)scratchpadManagedObjectContext;
+ (NSManagedObjectModel *)managedObjectModel;
+ (NSPersistentStoreCoordinator *)persistentStoreCoordinator;
+ (NSString *)applicationDocumentsDirectory;
这可以让我的应用程序委托之外的所有内容,并在我选择使用它时提供单例访问。但是,我仍然使用来自 App Delegate 的依赖注入(正如 mmalc 所说,它在我的代码中引入了不灵活)。我只是将所有“核心数据堆栈”代码移到 NSManagedObjectCONtext 类别中。
我喜欢传递引用,特别是因为我有一个很好的“便签本上下文”方法。这使我的视图控制器保持灵活,因为我没有将它们提交给“defaultManagedObjectContext”。
也与 iPhone 世界中的对话相关(并且可能与您的架构有关): NSFetchedResultsController and constructing NSFetchRequests
【讨论】:
我赞成让应用委托知道模型从哪里开始,让模型知道托管对象上下文在哪里。模型的核心数据——对我来说似乎是模型的实现细节,控制器类(如应用程序委托)应该只问“给我关于模型的信息”,模型应该知道如何回答那个问题。因此,通过控制器对象提供 Core Data 对象似乎是一种泄漏抽象。
【讨论】:
UIViewControllers 不需要与NSManagedObjectContext 混淆,他们应该与模型交谈并询问他们需要什么。获取该信息的机制与我的视图控制器无关。