这是另一种情况,在 NSFetchedResultController
上调用 performFetch
会中断并出现异常:
FATAL ERROR: The persistent cache of section information does not match the current configuration. You have illegally mutated the NSFetchedResultsController's fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:
但我还没有做过这些。要理解这个问题,请查看谓词:
predicate: (collection.identifier == ";root" AND doc.status == 0);
现在看看不匹配的缓存内容:
cached objects were: (
"MyDocument 'PL00002.jpeg' in set '/' (#2147483647)",
"MyDocument 'PL00003.jpeg' in set '/' (#2147483647)",
"MyDocument 'PL00003.pdf' in set '/' (#2147483647)",
"MyDocument 'PL00002.pdf' in set '/' (#2147483647)"
)
fetched objects are: (
"MyDocument 'PL00002.jpeg' in set '/' (#2147483647)",
"MyDocument 'PL00003.jpeg' in set '/' (#2147483647)",
"MyDocument 'PL00004.jpeg' in set '/' (#2147483647)",
"MyDocument 'PL00003.pdf' in set '/' (#2147483647)",
"MyDocument 'PL00002.pdf' in set '/' (#2147483647)",
"MyDocument 'PL00004.pdf' in set '/' (#2147483647)"
)
确实,有两个新的匹配对象。原因是两个新对象(PL00004.jpeg
和 PL00004.pdf
)之前的 status
属性值为 <>0 且我在代码中将它们的 status
更改回 0,因为它们开始满足某些外部条件(不是由用户操作触发)。
为了完整起见,下面是触发异常的代码:
- (void) reloadData
{
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
abort(); // I have actually better error handling
}
[_gridView reloadData];
}
另请注意:
- 没有其他
NSFetchedResultController
使用同名的缓存 _gridView
不是UITableView
,尽管它也显示实体集合。此详细信息不应该是相关的。- 没有调用任何
NSFetchedResultController
委托(delegate)方法,尤其是当我将两个对象的状态更改为 0 时 - 如果我在
performFetch:
之前清空缓存(或者没有缓存),一切都会正常运行。 - 在定期检查上面提到的外部条件结束时,我在 Controller 上调用此
reloadData
方法。 NSFetchedResultController
是使用nil
sectionNameKeyPath
创建的。- 正如所解释的,我从不改变
fetchedResultsController
:不改变它的谓词,不改变它的获取请求,不改变它的排序顺序,什么都没有。
我认为我不应该仅仅因为新对象现在满足谓词而得到这个异常。删除缓存可以避免异常,但只要我不明白为什么应该这样做,我就不认为这是一个修复。
知道我在这里想念什么吗?
编辑:这是所需的信息:
用于设置NSFetchedResultController
的代码。当用户选择一个集合时,这被称为:
- (void) displayCollection:(Collection *)aSet
{
self.currentCollection = aSet;
NSFetchRequest *fetchRequest = [[self fetchedResultsController] fetchRequest];
NSString *collectionIdentifier = @";root"; // no selection is like "select root collection";
if (aSet) {
collectionIdentifier = aSet.identifier;
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"collection.identifier == %@ and doc.status == %d", collectionIdentifier, upToDate];
[fetchRequest setPredicate:predicate];
[NSFetchedResultsController deleteCacheWithName:cacheName];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
abort(); // whatever
}
[_gridView reloadData];
}
fetchedResultsController
已初始化:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"DocInCollection" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"collection.identifier == %@ and doc.status == %d", @";root", upToDate];
[fetchRequest setPredicate:predicate];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"position" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:cacheName];
更新doc.status
时调用的代码:
- (void) setUpToDate
{
self.status = [NSNumber numberWithInt:upToDate];
NSError *error = nil;
[[self managedObjectContext] save:&error];
if (error) { } // whatever
[[self managedObjectContext] processPendingChanges];
}
cacheName
是一个全局常量 NSString
,upToDate
是一个枚举常量 (0)。
最后,由于应用程序使用了其他实体,因此该模型有点复杂。这是一个简化版本:
model http://emberapp.com/jdmuys/images/untitled-1/sizes/m.png
最佳答案
我会查看您的 sectionNameKeyPath
及其与正在突变的属性的关系(如果有)。从错误消息看来,您的部分正在以 Controller 不喜欢的方式发生变化。
不确定它是否相关,但我会对任何包含未转义分号的语句感到紧张。 ";root"
的谓词让我很痒。当然,它的任何问题都应该在编译时出现,但仍然......
更新:
出于病态的好奇心,我使用上述方法将测试数据模型和一些代码组合在一起。以下内容甚至无法编译:
NSManagedObject *cMO=[NSEntityDescription insertNewObjectForEntityForName:@"Collection" inManagedObjectContext:self.moc];
NSManagedObject *dMO=[NSEntityDescription insertNewObjectForEntityForName:@"Doc" inManagedObjectContext:self.moc];
[cMO setValue:@";root" forKey:@"identifier"];
[dMO setValue:[NSNumber numberWithInt:0] forKey:@"status"];
[cMO setValue:dMO forKey:@"doc"];
NSFetchRequest *fetch=[[NSFetchRequest alloc] init];
[fetch setEntity:[NSEntityDescription entityForName:@"Collection" inManagedObjectContext:self.moc]];
NSPredicate *p=[NSPredicate predicateWithFormat:@"identifier==";root" AND doc.status==0"];
[fetch setPredicate:p];
NSArray *a=[self performFetch:fetch];
NSLog(@"%@",a);
将谓词更改为:
NSPredicate *p=[NSPredicate predicateWithFormat:@"identifier == ';root' AND doc.status == 0"];
...编译并正常工作。我建议您将 ";root"
更改为 ';root'
至少用于故障排除。
关于cocoa - NSFetchedResultsController 缓存再次不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5393931/