ios - 获取请求返回旧数据

标签 ios macos core-data nsfetchrequest nsnotification

NSManagedObjectContextObjectsDidChangeNotification 上执行提取请求时,我得到了过时的结果。

例如,考虑包含可以使用 bool 属性 (softDeleted) 逻辑删除的文档的目录。提取请求应返回至少有一个未删除文档 (directoriesWithDocuments) 的所有目录。

初始状态是带有单个已删除文档的单个目录。 directoriesWithDocuments 返回一个空数组。

以下代码通过将 softDeleted bool 值设置为 NO 来恢复文档。

[_context.undoManager beginUndoGrouping];
[_context.undoManager setActionName:@"undelete"];
document.softDeleted = @(NO);
NSError *error;
BOOL success = [_context save:&error]; // This triggers the notification
[_context.undoManager endUndoGrouping];

保存会触发 NSManagedObjectContextObjectsDidChangeNotification。我希望 directoriesWithDocuments 返回目录,但它仍然返回一个空数组。

- (void)objectsDidChangeNotification:(NSNotification*)notification
{
    NSArray *objects = [self directoriesWithDocuments]; // Still empty!
}

然而,如果我立即或在下一个运行循环中执行 directoriesWithDocuments 保存上下文,它会按预期返回目录。

这是获取请求的代码:

- (NSArray*)directoriesWithDocuments
{
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY documents.softDeleted == NO"];
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Directory"];
    fetchRequest.predicate = predicate;
    fetchRequest.includesPendingChanges = YES; // Just in case
    NSError *error = nil;
    NSArray *objects = [_context executeFetchRequest:fetchRequest error:&error];
    return directories;
}

我怀疑上下文有某种缓存,用于获取请求,直到通知被处理后才会被清除。这是 Core Data 的行为方式吗?还是我做错了什么?

解决方法

我目前正在延迟执行这样的获取请求:

- (void)objectsDidChangeNotification:(NSNotification*)notification
{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        // HACK: Give time to Core Data to process pending changes or invalidate caches
        NSArray *objects = [self directoriesWithDocuments]; // Returns the directory as expected
    }];

}

实验

根据@MikePollard 的建议,我检查了 NSManagedObjectContextWillSaveNotificationNSManagedObjectContextDidSaveNotificationdirectoriesWithDocuments 的返回值。结果是(按顺序):

  1. NSManagedObjectContextObjectsDidChangeNotification:空(错误)
  2. NSManagedObjectContextWillSaveNotification:空(错误)
  3. NSManagedObjectContextDidSaveNotification:1 个目录(正确)

最佳答案

首先,看起来您在模型中定义了一个名为“deleted”的 bool 属性。

我记得这样做可能是一个严重的问题,因为它与 NSManagedObject isDeleted 冲突(在 KVC 级别)。您可能想要更改它以确保它不是罪魁祸首。

编辑

Thanks for replying. I used deleted as a simple example; it's not the actual attribute I'm using. Will change it to softDeleted to avoid confusion

我已经更新了下面的建议以匹配您示例中的 softDeleted


也就是说,我认为这里的工作归结为什么构成了 includesPendingChanges = YES 的“更改”的问题。

在上下文完成保存之前,唯一的“更改”是文档实体,而不是目录实体。

因此,当提取请求包含待定更改时,没有任何目录实体具有任何待定更改,因此您最终会得到之前的结果。

要验证该理论,请试一试:

[_context.undoManager beginUndoGrouping];
[_context.undoManager setActionName:@"delete"];
document.softDeleted = @(NO);
[document.directory willChangeValueForKey:@"documents"] // any attribute will do really
[document.directory didChangeValueForKey:@"documents"]
NSError *error;
BOOL success = [_context save:&error];
[_context.undoManager endUndoGrouping];

您使用伪造的 will/did changeValueForKey 所做的是“弄脏”关联的 Directory 对象。我的猜测是,它将被视为“已更改”,并因此包含获取结果。

关于ios - 获取请求返回旧数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22229617/

相关文章:

ios - performSegueWithIdentifier 不产生带有标识符错误的 segue

ios - UIProgressView 未按预期更新

ios - 保存 Int Array CoreData Swift 3 的最干净方法

objective-c - 使用 NIPagingScrollView 使 3 个 View 可见?

iphone - 使用 MagicalRecord 的多个数据库或仅将部分数据库同步到 iCloud

ruby - 无法在 MacOS Sierra 10.12.1 上安装 Jekyll

macos - 如何在 Mac 上降级和安装 ansible 1.9.4

macos - Duplicity 不喜欢 Mavericks 上的最大打开文件设置

ios - 映射核心数据的最佳库

ios - 核心数据、NSOrderedSet 和 iCloud