我有一个 Core Data 栈,它有一个带有 NSMainQueueConcurrencyType 的主要托管对象上下文。
用户可以在托管对象上启动一个可能需要很长时间的任务,因此它是在一个单独的上下文中执行的:
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[context setParentContext:mainMOC];
Person *samePerson = (Person *)[context objectWithID:person.objectID];
[context performBlock:^{
// BLOCK 1
// do lots of work
// then update the managed object
samePerson.value = someCalculatedValue;
// save the private context
NSError *error;
if (![context save:&error]) {
NSLog(@"Error: %@", error);
}
[mainMOC performBlock:^{
NSError *error;
if (![mainMOC save:&error]) {
NSLog(@"Error saving: %@", error);
}
}];
}];
这工作正常,主 MOC 得到正确更新,NSFetchedResultsController 连接到它正常执行,等等。
问题在于删除。我有这个设置来删除对象:
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[context setParentContext:mainMOC];
[context performBlock:^{
// BLOCK 2
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Person"];
NSError *error;
NSArray *all = [context executeFetchRequest:request error:&error];
if (!all) {
NSLog(@"Error fetching: %@", error);
} else {
for (NSManagedObject *person in all) {
[context deleteObject:person];
}
NSError *error;
if (![context save:&error]) {
NSLog(@"Error saving: %@", error);
}
[mainMOC performBlock:^{
NSError *error;
if (![mainMOC save:&error]) {
NSLog(@"Error saving: %@", error);
}
}];
}
}];
现在,如果我在执行long-duration task( block 1)期间执行此删除操作( block 2),则删除操作完成快速,并保存到主要上下文。 block 1 完成一段时间后,当它在最后保存 mainMOC 时,我们会遇到一个看似明显的崩溃:
CoreData could not fulfill a fault for ...
我的问题是:如何执行诸如 block 1 之类的任务,其对象可能被删除?
最佳答案
如果这些都是不能同时运行的后台任务,请尝试使用信号量来保护对它们的访问。
例如。对于实例变量:
dispatch_semaphore_t _backgroundProcessingSemaphore;
使用类似的东西延迟初始化:
- (dispatch_semaphore_t)backgroundProcessingSemaphore
{
if (!_backgroundProcessingSemaphore) {
_backgroundProcessingSemaphore = dispatch_semaphore_create(1);
}
return _backgroundProcessingSemaphore;
}
用以下内容包围关键代码:
dispatch_semaphore_wait(self.backgroundProcessingSemaphore, DISPATCH_TIME_FOREVER);
// Critical code
dispatch_semaphore_signal(self.backgroundProcessingSemaphore);
在任何时间点,只有一个关键代码段可以运行。如果信号量已被占用,调用 dispatch_semaphore_wait 的 block 将阻塞,直到它被释放。
您可能还想考虑拆分您的长期任务,以便它在您尚未这样做的情况下以离散的批处理运行 - 如果长时间运行的后台任务计时器即将到期,这将很有用仍有工作要做——您可以在下次启动时停止并从适当的点重新启动。
其他选项将涉及在 block 2 保存自身之前强制在 block 1 上进行保存,但这开始变得困惑。更容易确保两个竞争 block 不会重叠。
关于ios - 私有(private) NSManagedObjectContexts 和删除对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17986391/