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 等时,应用程序崩溃并出现此错误

由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[Poster setPosterID:]: unrecognized selector sent to instance 0xaa8b160”

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

我该如何解决这个问题?

4

2 回答 2

12

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

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

我不能告诉你如何使用 MagicalRecord 来做到这一点,但使用“普通核心数据”它会像这样工作:

创建托管对象上下文和持久核心协调器后,将两个 持久存储分配给存储协调器:

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,这将是此配置的适当方法。

于 2012-12-22T17:55:31.457 回答
3

您也可以尝试将指定的初始化程序-initWithEntity:insertIntoManagedObjectContext:与 nil 一起用于第二个参数。(根据我的经验,托管对象的某些方面在没有上下文的情况下可以正常工作;其他方面则不行。)

这个答案有一些进一步的解释。

于 2012-12-22T18:11:07.263 回答