在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的建议,我检查了directoriesWithDocuments
和NSManagedObjectContextWillSaveNotification
中NSManagedObjectContextDidSaveNotification
的返回值。结果是(按顺序):
NSManagedObjectContextObjectsDidChangeNotification
:空(错误)NSManagedObjectContextWillSaveNotification
:空(错误)NSManagedObjectContextDidSaveNotification
:1个目录(正确)答案 0 :(得分:1)
首先,看起来您的模型中定义了一个名为“deleted”的布尔属性。
我记得这样做可能是一个重大问题,因为它与NSManagedObject isDeleted
冲突(在KVC级别)。你可能想要改变它只是为了确保它不是罪魁祸首。
感谢您的回复。我用删除作为一个简单的例子;它不是 我正在使用的实际属性。将其更改为softDeleted以避免 混乱
我已在下面更新了我的建议,以匹配您示例中的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];
你正在做什么假意/做的changeValueForKey是“脏”关联的目录对象。我的猜测是,它将被视为“已更改”,因此包括获取结果。
答案 1 :(得分:0)
让我觉得谓词将被翻译成一个SQL语句,所以在保存到达DB之前你不会得到你想要的结果......(不是你想要的那个只需阅读NSFetchRequest
文档。)
因此,请尝试执行NSManagedObjectContextDidSaveNotification
。
我打赌如果你打开-com.apple.CoreData.SQLDebug 1,你会看到SQL语句。