[英]Fetch request returns old data
在NSManagedObjectContextObjectsDidChangeNotification
执行提取请求时,我得到的结果已经过时。
例如,考虑包含文档的目录,这些文档可以使用布尔属性( softDeleted
)进行逻辑删除。 提取请求应返回具有至少一个未删除文档的所有目录( directoriesWithDocuments
)。
初始状态是具有单个已删除文档的单个目录。 directoriesWithDocuments
返回一个空数组。
以下代码通过将softDeleted
布尔值设置为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;
}
我怀疑上下文具有某种类型的缓存,用于获取请求,直到处理通知后才会清除。 这是核心数据的预期表现吗? 还是我做错了什么?
我目前正在像这样延迟获取请求的执行:
- (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的建议,我检查了NSManagedObjectContextWillSaveNotification
和NSManagedObjectContextDidSaveNotification
中directoriesWithDocuments
的返回值。 结果是(按顺序):
NSManagedObjectContextObjectsDidChangeNotification
:空(错误) NSManagedObjectContextWillSaveNotification
:空(错误) NSManagedObjectContextDidSaveNotification
:1个目录(正确) 首先,看起来您在模型中定义了一个布尔属性,称为“ deleted”。
我记得这样做可能是一个重大问题,因为它与NSManagedObject isDeleted
冲突(在KVC级别上)。 您可能想要更改它,以确保它不是罪魁祸首。
感谢回复。 我以删除为例。 这不是我正在使用的实际属性。 将其更改为softDeleted以免造成混淆
我在下面更新了我的建议,以使其与示例中的softDeleted
相匹配。
就是说,我认为这里的工作归结为由includePendingChanges includesPendingChanges = YES
构成“更改”的问题。
在上下文完成其保存之前,唯一的“更改”是对文档实体,而不是目录实体。
因此,当获取请求包含待定更改时,不存在任何待定更改的Directory实体,因此您将获得先前的结果。
为了验证该理论,请尝试一下:
[_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对象。 我的猜测是,它将被视为“已更改”,因此包括了获取结果。
令我惊讶的是,该谓词将被转换为SQL语句,因此在保存命中数据库之前,您将无法获得所需的结果...(不是那会导致您仅通过读取NSFetchRequest
文档。)
因此,请尝试通过NSManagedObjectContextDidSaveNotification
进行获取。
我敢打赌,如果您打开-com.apple.CoreData.SQLDebug 1,您将看到SQL语句。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.