通过MagicalRecords在不同的线程中使用NSManagedObject

时间:2014-01-07 16:49:59

标签: ios core-data magicalrecord

我在主线程中创建实体Artist, 然后在后台线程中传递它并与实体相册相关联。

如何正确完成?

- (IBAction)add:(id)sender
{
    Artist *artist = [Artist MR_createEntity];
    artist.title = @"Eminem";

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
        // here a large calculation
        Album *album = [Album MR_createEntity];
        album.title = @"Album 1";
        [artist setAlbums:[NSSet setWithArray:@[album]]];

        dispatch_async(dispatch_get_main_queue(),^{
            [artist.managedObjectContext MR_saveToPersistentStoreAndWait];
        });
    });
}

错误:

MagicalRecordTest[2008:1803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Illegal attempt to establish a relationship 'albums' between objects in different contexts (source = <Artist: 0x15eaa2d0>

2 个答案:

答案 0 :(得分:5)

您违反了核心数据的主要规则之一。只能在创建它们的线程上访问NSManagedObjectContext及其关联的NSManagedObject实例。您可以传递NSManagedObjectID个实例,但不能传递NSManagedObject个实例。

此外,当您在两个NSManagedObject实例之间创建关系时;两个实例必须来自同一个NSManagedObjectContext,否则您将收到上述错误。

取代上面的方法,重新获取块中的Artist。我可以提供有关如何使用Core Data执行此操作的示例代码,但您需要研究如何使用MagicalRecord执行此操作。

答案 1 :(得分:3)

Marcus是正确的,因为您需要了解您正在使用的上下文,并且只需要在单个队列或线程中使用它们。 MagicalRecord有一个很好的API来管理它。在你的情况下,你应该做更多的事情:

- (void) add;
{
    NSManagedObjectContext *mainContext = [NSManagedObjectContext MR_defaultContext];
    Artist *artist = [Artist MR_createInContext:mainContext];
    [mainContext MR_saveToPersistentStoreAndWait];

    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
        Artist *localArtist = [artist MR_inContext:localContext];
        localArtist.title = @"Album...";
    }];
}

MagicalRecord将设置保存队列并在正确的位置执行操作,只要您记住第一个,就不能在NSManagedOjbectContexts之间传输临时对象。其次,必须为每个线程/队列/块使用单独的上下文。在这种情况下,localContext是为您创建的,一旦块完成,MagicalRecord将尝试为您保存本地/临时上下文。