ios - 私有(private) NSManagedObjectContexts 和删除对象

标签 ios core-data

我有一个 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/

相关文章:

cocoa - NSFetchedResultsController Mac OSX Cocoa 等效项

ios - ld : library not found for -lJTCalendar on iOS Simulator

core-data - Xcode 4 数据模型版本控制错误?

swift - 如何使用完成处理程序在 core data swift 5 中获取过滤数据结果

objective-c - 使用 OCMock 和 Core Data 测试 Controller 方法

objective-c - NSManagedObjectContext 通过通知中心问题在多个线程上保存/合并

ios - dispatch_queue_t 是串行队列那么为什么它甚至存在于多任务概念中?

javascript - 加载 web View 中的 NSURLSession/NSURLConnection HTTP 加载失败(kCFStreamErrorDomainSSL,-9814)?

iphone - 核心数据 SQLite 约束失败

ios - 从较小的尺寸放大视频(重新缩放)