核心数据-后台线程中的更新实体会自动更改主线程中的 NSManagedObject 而无需合并-为啥?

Posted

技术标签:

【中文标题】核心数据-后台线程中的更新实体会自动更改主线程中的 NSManagedObject 而无需合并-为啥?【英文标题】:Core Data - update entity in background thread automatically changes NSManagedObject in Main Thread without merging- why?核心数据-后台线程中的更新实体会自动更改主线程中的 NSManagedObject 而无需合并-为什么? 【发布时间】:2011-12-18 10:01:54 【问题描述】:

我目前正在学习核心数据。 Core Data 很棒,但我无法解释后台线程中第二个托管对象上下文的行为。

我有一个名为 TestEntity 的实体,它有 2 个属性(testId 和 testDescription) 在主线程上,我获取 testId = 1 的实体并将这个托管对象存储到一个实例变量中。

    NSEntityDescription *entityDescription = [NSEntityDescription
                                          entityForName:@"TestEntity" inManagedObjectContext:self.managedObjectContext];

NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];

NSNumber *testId = [NSNumber numberWithInt:1];
NSPredicate *predicate = [NSPredicate predicateWithFormat:
                          @"testId == %@", testId];
[request setPredicate:predicate];

NSError *error = nil;
NSArray *array = [self.managedObjectContext executeFetchRequest:request error:&error];

t1 = [[array objectAtIndex:0] retain];

TestThread *tt = [TestThread new];

NSOperationQueue *queue = [NSOperationQueue new];
[queue addOperation:tt];

[queue waitUntilAllOperationsAreFinished];
NSLog(@"%@", [t1 valueForKey:@"testDescription"]);

然后是使用一个名为 TestThread 的 NSOperationQueue 启动一个 NSOperation。 在这个 TestThread 的 main 方法中,我创建了第二个托管对象上下文,获取与主线程相同的实体 (testId = 1),更改 testDescription 属性并保存新的上下文而不会出现任何错误。

    tgAppDelegate *delegate = [[NSApplication sharedApplication] delegate];

self.context = [[[NSManagedObjectContext alloc] init] autorelease];
[context setPersistentStoreCoordinator:delegate.persistentStoreCoordinator];


NSEntityDescription *entityDescription = [NSEntityDescription
                                          entityForName:@"TestEntity" inManagedObjectContext:self.context];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];

// Set example predicate and sort orderings...
NSNumber *testId = [NSNumber numberWithInt:1];
NSPredicate *predicate = [NSPredicate predicateWithFormat:
                          @"testId == %@", testId];
[request setPredicate:predicate];

NSError *error = nil;

NSArray *array = [context executeFetchRequest:request error:&error];
TestEntity *t1 = [array objectAtIndex:0];

t1.testDescription = @"abc";
[context save:&error];
if (error) 
    // do something

我无法解释自己的行为是,NSLog 输出之后

[queue waitUntilAllOperationsAreFinished];

具有在我的后台线程中更新的相同字符串值。

abc

我对核心数据和多线程的理解是我必须在上下文之间进行显式合并。 在我的测试应用中没有合并。

谁能解释为什么会这样?

【问题讨论】:

【参考方案1】:

默认情况下,获取请求会将对象作为错误返回,因此在您访问它之前不会实际加载它们的内容(您可以在this link 下了解有关错误的更多信息)。

要查看您的预期行为,请在启动第二个线程之前尝试记录 t1.testDescription 的原始值。

你也可以设置

self.context.returnObjectsAsFaults = NO;

但这可能会对您的应用程序的内存占用产生负面影响。

【讨论】:

谢谢,您的链接帮助我理解了这一点

以上是关于核心数据-后台线程中的更新实体会自动更改主线程中的 NSManagedObject 而无需合并-为啥?的主要内容,如果未能解决你的问题,请参考以下文章

iOS 在后台保存主线程 NSManagedObjectContext 更改

在后台和主线程中使用托管对象上下文

Python 3 - 主线程未检测到后台线程中的KeyboardInterrupt,直到用户将鼠标悬停在GUI窗口上

核心数据:大后台抓取能否阻塞主线程抓取请求?

核心数据在后台线程上缓慢处理更新

在后台线程中更新托管对象上下文