Cocoa 使用MagicalRecord在后台保存的设计策略

Cocoa 使用MagicalRecord在后台保存的设计策略,cocoa,core-data,concurrency,magicalrecord,Cocoa,Core Data,Concurrency,Magicalrecord,最近我启动了一个新的应用程序,只需要一个商店(没有基于文档的应用程序)。有一段时间,我非常高兴地认为我终于可以摆脱在NSManagedObjectContext周围乱扔东西了。。。直到我想在后台保存:-( 现在我对自己的代码感到困惑。例如: - (void)awakeFromInsert { [super awakeFromInsert]; [self resetCard]; self.creationDate = TODAY; self.dictionary =

最近我启动了一个新的应用程序,只需要一个商店(没有基于文档的应用程序)。有一段时间,我非常高兴地认为我终于可以摆脱在NSManagedObjectContext周围乱扔东西了。。。直到我想在后台保存:-(

现在我对自己的代码感到困惑。例如:

- (void)awakeFromInsert
{
    [super awakeFromInsert];
    [self resetCard];
    self.creationDate = TODAY;
    self.dictionary = [Dictionary activeDictionary];
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center postNotificationName:NOTE_NEWCARD object:self];    
}
[Dictionary activeDictionary]是一个NSManagedObject静态函数,返回指向在主线程中创建的NSManagedObject的指针。这将在后台保存过程中导致跨/上下文错误。因为我的程序总是从同一个存储读取,我想我可以避免编写以下内容:

[Dictionary activeDictionaryWithContext:...]
我认为使用MagicalRecord,只要我始终使用相同的后端,就可以避免传递上下文指针。我应该使用哪个函数来获取该上下文

[NSManagedObjectContext MR_defaultContext]
[NSManagedObjectContext MR_context]
[NSManagedObjectContext MR_contextForCurrentThread]
在本例中,对象在通知中发送自身,这几乎被授权会导致更多冲突

  • 在通知的情况下,我是否应该始终只发送objectID
在我看来,我的对象只有在主上下文中运行时才应该发出副作用操作/通知。但是,其中一些副作用操作会更改我的对象图,从而创建其他实体的新实例

  • 如果使用[MagicalRecord MR_saveAll]保存,是否可以安全地省略我提到的两个有问题的函数调用

  • 我是否应该假设新后台保存上下文的对象将是主线程中对象的精确副本,而不调用这些额外函数

现在我遇到了一些问题,因为我从来没有想到awakeFromInsert会为同一商店的同一对象运行几次。我在想这样的事情:

- (void)awakeFromInsert
{
    [super awakeFromInsert];
    if ([self managedObjectContext] == [NSManagedObjectContext MR_defaultContext]) {
        [self resetCard];
        self.creationDate = TODAY;
        self.dictionary = [Dictionary activeDictionary];
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
        [center postNotificationName:NOTE_NEWCARD object:self];    
    }
}

这将使我的awakeFromInsert代码只运行一次,但不会在后台保存上下文中运行。我担心这样做会丢失信息

虽然您肯定可以通过这种方式发送对象通知,但我建议不要这样做。记住,即使CoreData中有新的父子上下文,NSManagedO对象不是线程安全的。如果创建或导入对象,则需要先保存它们,然后才能在其他上下文中使用它们

MagicalRecord为后台保存提供了一个相对简单的API:

[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext){
    MyEntity *newEntity = [MyEntity MR_createInContext:localContext];

    //perform other entity operations here
}];
此块为您完成所有工作,而无需担心如何正确设置NSManagedObjectContext

不应在通知中传递NSManagedObjects的另一个原因是,您不知道将在哪个线程上接收通知。这可能会导致崩溃,因为NSManagedObjects不是线程安全的


您提供的通知方法的另一种替代方法是向NSManagedObjectContextDidSaveNotification添加观察者,并合并对该通知所做的更改。这将仅在保存对象后触发,并且对于通过父子关系或持久存储跨上下文是安全的(老路).

谢谢,我使用的是MagicalRecord 2.0.7,虽然我只使用一个上下文,但简单的MR_save会带来一些麻烦,因为它使用的是它创建的第二个上下文。最糟糕的是,通知来自第三个上下文?!?我知道NSManagedObject不是线程安全的,我的问题是我应该如何处理它以及会发生什么在MR_save期间。我看到正在创建第二个上下文,因此将对同一存储区的对象调用两次awakeFromInsert。如果awakeFromInsert代码仅在当前上下文是主线程时运行,我担心会丢失信息。现在更新问题…awakeFromInsert将被调用两次,因为您正在创建两个单独上下文上的实例。我认为您需要的是创建对象,然后保存,然后在第二个上下文中加载对象。在本文发布两天后,我发现如果不在当前上下文中运行,我必须编写条件以排除awakeFromInsert。我非常确定我只使用一个上下文。MR_save确实创建了一个新的上下文一个并重新创建所有my对象的实例,因此执行两次my awakeFromInsert。使用标准:save:&error不会触发第二次调用。上下文合并是由Magic处理的吗?还是我需要AppDelegate来处理?