我们创建了一个存储库层,用于与Core Data进行交互,其中包含allItems()
,addItem:(Item*)item
等方法,其中item是NSManagedObject子类。当我们需要保存项时,我们在存储库上调用方法,将子类实例作为参数传递。但是,这不起作用,因为我们无法使用init
初始化程序,并且上下文隐藏在存储库中。
当您拥有这样的架构时,传输对象的最佳方法是什么?让一个ItemDTO绕过一个选项吗?或者有更好的方法来解决这个问题,例如根本不使用子类NSManagedObject,只使用有效的键/值。
答案 0 :(得分:5)
我说你使用的架构不适合核心数据。要继续使用它(你应该),你必须做两件事之一。我假设您的“存储库层”实现为单例,或者至少创建新托管对象的对象可以访问它。
如果您发现自己正在与框架作斗争并提出过多的抽象,那么您做错了。
答案 1 :(得分:3)
通常,您希望创建NSManagedObject
子类的控制器具有指向NSManagedObjectContext
的指针。通过这种方式,您确实可以调用初始化程序。
您尝试做的事情的问题是没有上下文,项目不能存在。这是故意完成的,以便Core Data知道您是在讨论新对象还是已经在持久存储中的对象。
您可以使用DTO,但最终会出现大量重复,因此很快就会变得难看。在我看来,您应该考虑让您的控制器知道核心数据上下文,以便它可以正确地检索或初始化项目(托管对象),并基本上使用NSManagedObjectContext
作为您的存储库层。
请记住,NSManagedObjectContext
是一个持久性抽象层,您可以根据需要使用其他持久性存储实现进行备份,包括您自己的custom ones。
答案 2 :(得分:1)
我写了复制粘贴了一个示例项目,它隐藏了模型自定义类的上下文:branch 10583736。
(这不是最终的生产代码,只是一个简单的例子,不要指望它处理多线程或奇怪的错误)
将上下文隐藏到自定义类只是定义自定义方法来处理通常会请求上下文并使用它的每种情况。
您可以为商店图层定义一个类,而不会暴露上下文:
@interface DataStore : NSObject
+ (id)shared;
- (void)saveAll;
- (NSEntityDescription *)entityNamed:(NSString *)name;
/* more custom methods ... */
- (NSManagedObject *)fetchEntity:(NSEntityDescription *)entity withPredicate:(NSPredicate *)predicate;
@end
我建议为所有自定义模型类使用共同的祖先来保存一些输入。此类可以是唯一直接与DataStore
交互的类。它无权访问上下文。
@interface DataObject : NSManagedObject
+ (NSString *)entityName;
+ (NSEntityDescription *)entity;
- (void)save;
/* more custom methods ... */
@end
最后,您的模型自定义类定义了您可能需要利用超类提供的任何方法的任何方法:
@interface Card : DataObject
@property (nonatomic, retain) NSString * question;
@property (nonatomic, retain) NSString * answer;
@property (nonatomic, retain) Deck *deck;
/* return a new card */
+ (Card *)card;
/* more custom methods ... */
@end
master 分支有一种更常用的方法,其中模型类获取上下文并使用它。