如何在不保存Core Data模型的情况下使用它们?

8
我正在编写一个应用程序,使用MagicalRecord作为与Core Data交互的框架。该应用从服务器获取海报数组,然后显示它们。用户还可以在应用上创建海报,如果需要,可以将其上传到服务器。
因此,由用户创建的海报使用Core Data存储在本地数据库中,而从服务器获取的海报仅应在应用中显示,但不保存在本地。我如何使用相同的Poster类(现在是NSManagedObject的子类)来处理这两种情况?
以下是我的类:
@interface Poster : NSObject
@property (nonatomic, retain) NSNumber * posterID;
@property (nonatomic, retain) NSString * artists;
@end

当我从服务器获取海报数组时,我会分配一个新的海报并分配属性:
Poster *poster = [[Poster alloc] init];
if ([dict objectForKey:@"id"]) poster.posterID = [dict objectForKey:@"id"];
if ([dict objectForKey:@"artists"]) poster.artists = [dict objectForKey:@"artists"];

但是当到达链接的poster.posterID = [dict etc etc时,应用程序会崩溃并出现以下错误:

终止应用程序,原因是未捕获的异常 'NSInvalidArgumentException',原因:'-[Poster setPosterID:]:向实例0xaa8b160发送无法识别的选择器'

如果我使用Poster *poster = [Poster createEntity];创建新对象,而不是Poster *poster = [[Poster alloc] init];,应用程序不会崩溃,但是当我保存上下文时,我发现从服务器获取的所有海报都已保存在本地。

我该怎么解决这个问题?

2个回答

12

您不能仅仅使用alloc/init来创建托管对象,因为托管对象必须与托管对象上下文相关联。poster.posterID = ...会导致崩溃,因为动态创建的访问方法在没有托管对象上下文的情况下无法工作。(更正:正如@noa所说,只要使用指定的初始化器,就可以创建不需要托管对象上下文的对象。但是这些对象对于任何获取请求都不会“可见”。)

要创建不应保存到磁盘的托管对象,您可以使用两个持久性存储库:一个SQLite存储库和一个单独的内存存储库。

我无法告诉您如何在MagicalRecord中实现这一点,但是在“纯Core Data”中,它将按以下方式工作:

在创建托管对象上下文和持久核心协调器之后,您将为存储协调器分配两个持久性存储库:

NSPersistentStore *sqliteStore, *memStore;

sqliteStore = [coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error];
if (sqliteStore == nil) {
    // ...
}
memStore = [coordinator addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:&error];
if (memStore == nil) {
    // ...
}

稍后,当您向上下文中插入新对象时,您将新对象与SQLite存储或内存存储关联:

Poster *poster = [NSEntityDescription insertNewObjectForEntityForName:@"Poster" inManagedObjectContext:context];
[context assignObject:poster toPersistentStore:memStore];
// or: [context assignObject:poster toPersistentStore:sqliteStore];
poster.posterID = ...;
poster.artists = ...;

只有分配给SQLite存储的对象才会保存到磁盘中。 如果你重新启动应用程序,则分配给内存存储的对象将会消失。 我认为,没有明确分配给存储库的对象会自动分配给第一个存储库,在本例中应该是SQLite存储库。

我还没有使用过MagicalRecord,但我看到有MR_addInMemoryStoreMR_addSqliteStoreNamed方法,这些方法应该是此配置的适当方法。


不错的答案,但根据我的经验,如果使用指定的初始化程序(第二个参数为nil),动态访问器仍将在没有MOC的情况下工作。 - paulmelnikow
@noa:感谢您的反馈,您说得对,对象可以在没有MOC的情况下创建(我会修复我的回答中的这一部分)。- 这种设置的优点是临时对象位于同一个MOC中,因此可以使用fetch请求或fetched results controller显示它们。 OP说:“从服务器获取的海报应该只在应用程序中显示”,因此我认为这个解决方案更好。 - Martin R

3
你也可以尝试使用指定的初始化器-initWithEntity:insertIntoManagedObjectContext:,第二个参数设置为nil。(根据我的经验,某些受管理对象的方面可以正常工作而不需要上下文;其他则不行。)更多解释请参考这篇回答

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接