托管对象上下文不保存到持久性存储

时间:2012-02-03 18:00:22

标签: objective-c ios core-data nsmanagedobject nsmanagedobjectcontext

我有一个线程操作,创建一个新的托管对象,将其保存到持久性存储,然后通过NSNotification将新对象的objectID传递给主线程进行进一步处理

但是,当我尝试从主线程访问新创建的托管对象时,我在后台线程上设置的所有值都返回为空。

**后台线程

// create a new managed object context for this thread  
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];  
[context setPersistentStoreCoordinator:[appDelegate persistentStoreCoordinator]];
[context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];

// create the object
MyObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"MyObject" inManagedObjectContext:context];  
[newManagedObject setAValue:@"A"];  
[newManagedObject setBValue:@"B"];  
[newManagedObject setCValue:@"C"];  

// save it on the main thread
[context performSelectorOnMainThread:@selector(save:) withObject:nil waitUntilDone:NO];

// post notification to main thread, pass the objectID
NSMutableDictionary *userInfo = [NSDictionary dictionaryWithObject:[newManagedObject objectID] forKey:@"objectID"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"doneInsertingObject" object:userInfo];  
[context release];

**主线程

...
// register notification for background thread
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeContextChanges:) name:NSManagedObjectContextDidSaveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomethingWithObject:) name:@"doneInsertingObject" object:nil];
...

 - (void)doSomethingWithObject:(NSNotification*)noif
{
    if([NSThread isMainThread] == NO)
    {
        // run this on the main thread
        [self performSelectorOnMainThread:_cmd withObject:noif waitUntilDone:NO];
        return;
    }

    // get managed object from objectID
    NSDictionary *userInfo = [noif userInfo];
    MyObject *object = (MyObject*)[appDelegate.managedObjectContext objectWithID:[userInfo valueForKey:@"objectID"]];
    [appDelegate.managedObjectContext refreshObject:object mergeChanges:YES];

    // these should return 'A, B, C' but all three return 'nil'
    NSLog(@"aValue: %@", object.aValue);
    NSLog(@"bValue: %@", object.bValue);
    NSLog(@"cValue: %@", object.cValue);
}

// merge background thread moc with main moc
- (void)mergeContextChanges:(NSNotification *)notification
{
    if([NSThread isMainThread] == NO)
    {
        // run this on the main thread
        [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO];
        return;
    }

    // fault all updated objects
    NSSet *updated = [[notification userInfo] objectForKey:NSUpdatedObjectsKey];
    for(NSManagedObject *thing in updated)
    {
        [[appDelegate.managedObjectContext objectWithID:[thing objectID]] willAccessValueForKey:nil];
    }

    // merge changes to the main managed object context
    [appDelegate.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];

    // force processing of any pending changes
    [appDelegate.managedObjectContext processPendingChanges];
}

我尝试过更改合并政策,但没有区别。

我已经尝试将日志记录添加到上下文合并方法,并且我已经确认在调用主线程上的doSomethingWithObject:方法之前从后台线程接收“插入”通知。

为什么我的数据没有更新到持久性商店?

2 个答案:

答案 0 :(得分:3)

我无法看到您为后台线程保存上下文的位置。如果是这条线

// save it on the main thread
[context performSelectorOnMainThread:@selector(save:) withObject:nil waitUntilDone:NO];

我不知道它是否正确。您已从创建它的线程中保存上下文,而不是在主线程中保存。

[context save:&error];

有关详细信息,我建议您阅读Marcus Zarra撰写的文章importing-and-displaying-large-data-sets-in-core-data。您可以在最后找到示例代码。此外,您还可以在using-core-data-on-multiple-threads中找到更多信息。

希望它有所帮助。

答案 1 :(得分:1)

您的NSManagedObjectContext必须保存在其创建的主题上(正如@Flex_Addicted一样)。

保存在后台线程后,将发布一条通知,告知您将更改从后台上下文合并到主上下文。

苹果文档显示“在后台线程中保存容易出错” - 这与使用其他NSManagedObjectContext无关。他们说如果你有1个上下文,并且你试图将保存操作发送到后台 - 这很容易出错。如果您有多个上下文,则它们一次只能在一个线程中使用。