在我的数据加载类中,我在这里设置了父/子 mocs 来执行
后台线程的工作:
dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSManagedObjectContext *mainMOC = self.managedObjectContext;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
你不应该那样做。改为这样做。
NSManagedObjectContext *mainMOC = self.managedObjectContext;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
确保您通过performBlock 访问 MOC。例如,
[moc performBlock:^{
// Anything at all involving this MOC or any of its objects
}];
当 json 数据完成后,我尝试执行保存操作
使用以下宏:
考虑用这样的方式保存。保存完成后将调用您的完成块。
- (void)saveMOC:(NSManagedObjectContext*)moc
completion:(void(^)(NSError *error))completion {
[moc performBlock:^{
NSError *error = nil;
if ([moc save:&error]) {
if (moc.parentContext) {
return [self saveMOC:moc.parentContext completion:completion];
}
}
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(error);
});
}
}];
}
[self saveMOC:moc completion:^(NSError *error) {
// Completion handler is called from main-thread, after save has finished
if (error) {
// Handle error
} else {
}
}];
编辑
如果 moc.parentContext 是主要并发类型,此代码将崩溃。 –
世界
我发布的代码没有内在的原因会导致父 MOC 为 NSMainQueueConcurrencyType 的崩溃。自从父/子添加到 Core Data 以来,它就支持成为父上下文。
也许我错过了一个错字,所以我直接从这个答案复制/粘贴saveMOC:completion:,并编写了以下测试助手。
- (void)testWithChildConcurrencyType:(NSManagedObjectContextConcurrencyType)childConcurrencyType
parentConcurrencyType:(NSManagedObjectContextConcurrencyType)parentConcurrencyType {
NSAttributeDescription *attr = [[NSAttributeDescription alloc] init];
attr.name = @"attribute";
attr.attributeType = NSStringAttributeType;
NSEntityDescription *entity = [[NSEntityDescription alloc] init];
entity.name = @"Entity";
entity.properties = @[attr];
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] init];
model.entities = @[entity];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
[psc addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:NULL];
NSManagedObjectContext *parent = [[NSManagedObjectContext alloc] initWithConcurrencyType:parentConcurrencyType];
parent.persistentStoreCoordinator = psc;
NSManagedObjectContext *child = [[NSManagedObjectContext alloc] initWithConcurrencyType:childConcurrencyType];
child.parentContext = parent;
NSManagedObject *obj = [NSEntityDescription insertNewObjectForEntityForName:@"Entity" inManagedObjectContext:child];
[obj setValue:@"value" forKey:@"attribute"];
XCTestExpectation *expectation = [self expectationWithDescription:[NSString stringWithFormat:@"save from %@ to %@ finished", concurrencyTypeString(childConcurrencyType), concurrencyTypeString(parentConcurrencyType)]];
[self saveMOC:child completion:^(NSError *error) {
// Verify data saved all the way to the PSC
NSManagedObjectContext *localMoc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
localMoc.persistentStoreCoordinator = psc;
NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:@"Entity"];
XCTAssertEqualObjects(@"value", [[[localMoc executeFetchRequest:fr error:NULL] firstObject] valueForKey:@"attribute"]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:10 handler:nil];
}
然后,我为每个可能的父/子关系编写了一个测试。
- (void)testThatDoingRecursiveSaveFromPrivateToPrivateWorks {
[self testWithChildConcurrencyType:NSPrivateQueueConcurrencyType
parentConcurrencyType:NSPrivateQueueConcurrencyType];
}
- (void)testThatDoingRecursiveSaveFromPrivateToMainWorks {
[self testWithChildConcurrencyType:NSPrivateQueueConcurrencyType
parentConcurrencyType:NSMainQueueConcurrencyType];
}
- (void)testThatDoingRecursiveSaveFromMainToPrivateWorks {
[self testWithChildConcurrencyType:NSMainQueueConcurrencyType
parentConcurrencyType:NSPrivateQueueConcurrencyType];
}
- (void)testThatDoingRecursiveSaveFromMainToMainWorks {
[self testWithChildConcurrencyType:NSMainQueueConcurrencyType
parentConcurrencyType:NSMainQueueConcurrencyType];
}
那么,我错过了什么?
在我写这篇文章的时候,我想起了一个 360iDev 演示文稿,演示者说你不能在 NSMainQueueConcurrencyType 上下文中调用 performBlock。当时,我以为他只是说错话了,意思是坐月子,但也许社区对此有些困惑。
您不能在NSConfinementConcurrencyType MOC 上调用performBlock,但NSMainQueueConcurrencyType 完全支持performBlock。