为什么 NSFetchedResultsController 无法正确加载部分标题?
我正在使用 NSFetchedResultsController 和 UITableViewController。
我在核心数据模型中创建了一个瞬态字段,用作 UITableView 部分的标签。该字段的名称是“sectionIndex”。在我的应用程序中,“客户端”实体有许多“作业”(1 到多个) - 因此我检索作业的查询按其关联的“客户端”名称对它们进行分组(通过部分)。
我已在我的代码库中将此方法实现为“作业”实体上的类别。
@implementation Job (TransientMethods)
- (NSString*)sectionIndex {
NSLog(@"JobWrapper.Job.sectionIndex: %@", self.client.name);
return self.client.name;
}
@end
并且字符串“sectionIndex”作为sectionNameKeyPath参数传递给NSFetchedResultsController的init方法。
如果我从模拟器中删除应用程序 - 那么应用程序第一次运行时,作业的首页会根据此处列出的sectionIndex 方法,按作业的 Client.name 正确检索作业并对其进行分组。在日志中,我可以从字面上看到此sectionIndex方法被调用多次。
但是,应用程序的后续运行不会调用sectionIndex方法...但是,部分标签仍然显示上次运行的值。这是怎么回事?运行之间是否存在一些神奇的缓存?
这种行为会导致更大的问题。在查看 UITableView 时,如果我使用稍微不同的谓词释放并分配 NSFetchedResultsController,并且结果集大小相同,...那么这些相同的原始部分名称将显示在所有新结果中!
当然,没有新的日志条目。这意味着永远不会查找列,这意味着代码永远不会调用或查找瞬态字段。就好像这些场没有断层一样。
现在,如果备用查询返回不同数量的结果,则加载节名称。 IE:在这种情况下,日志会在每次按下栏按钮时显示调用的“sectionIndex”方法以及 UITableView 中显示的相应标签。
这太疯狂了 - 如果我有 2 个“活动”作业和 2 个“非活动”作业,并且我使用条形按钮在相应查询之间来回切换...那么与初始查询关联的任何部分标签都会显示给所有用户后续表视图。
似乎只有当结果集中有不同的结果数时,FetchedResultsController 才会调用sectionNameKeyPath 字段?实际结果是不同的 - 作业名称在实际行中正确显示 - 但同样,我不认为部分标签有错误或正确询问 NSFetchedResultsController 部分标签。我正在使用以下内容:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
int count = [[results_ sections] count];
if (count > section) {
id <NSFetchedResultsSectionInfo> sectionInfo = [[results_ sections] objectAtIndex:section];
return [sectionInfo name];
}
return nil;
}
其中 results_ 是我为每个查询重新构建的 NSFetchedResultsController 。
我错过了什么吗?有没有办法手动清除核心数据缓存,使其不再那么智能,并且在每次查询时肯定会查找sectionNameKeyPath?
就其价值而言,我取消了 xcdatamodel 中字段的“瞬态”选项,但得到了相同的结果。
最后一个异常现象是,当我将第一个作业创建为“非活动”(不是默认的启动视图)时 - 如果我还创建了“活动”作业...“非活动”部分标签将粘贴在两者上。此外,当我关闭应用程序并重新开始时......非活动部分标签仍然显示——即使在标题屏幕上,我正在显示活动作业,它应该显示完全不同的标签。
我不得不认为这是一个核心数据问题。重新启动应用程序会返回如此不正常的数据,这是没有意义的。
I am using NSFetchedResultsController along with a UITableViewController.
I've created a transient field in my Core Data model to use as a label for my UITableView sections. The name of the field is "sectionIndex". In my application, a "Client" entity has many "Jobs" (1 to many) - so my query to retrieve Jobs groups them (via section) by their associated "Client's" name.
I've implemented this method in my code base as a Category on the 'Job' entity.
@implementation Job (TransientMethods)
- (NSString*)sectionIndex {
NSLog(@"JobWrapper.Job.sectionIndex: %@", self.client.name);
return self.client.name;
}
@end
and the string "sectionIndex" is passed to the init method for NSFetchedResultsController as the sectionNameKeyPath argument.
If I erase the app from the simulator - then the first time the application runs, the front page of Jobs correctly retrieves and groups the Jobs by the Job's Client.name per the sectionIndex method listed here. In the logs, I can literally see this sectionIndex method invoked multiple times.
However, subsequent runs of the application do NOT invoke the sectionIndex method ... and yet, the section labels still show up with the values from the last run. How is that happening? Is there some magic caching going on between runs?
That behavior then leads to a bigger problem. While looking at the UITableView, if I release and alloc the NSFetchedResultsController with a slightly different predicate and if the result set is the SAME SIZE, ... then these same, original section names show up for all of the NEW results!
And of course, there are no new log entries. This implies the columns are never being looked up which implies the code never invokes or looks up the transient fields. It is as though those fields are not faulting.
Now, if the alternate query returns a DIFFERENT number of results, then the sections names ARE loaded. IE: in that case, the logs show - on every bar button push - the 'sectionIndex' method being invoked and the corresponding labels showing up in the UITableView.
This is crazy - if I have 2 "active" Jobs and 2 "inactive" Jobs and I am using a bar button to switch back and forth between corresponding queries ... then whichever section labels were associated with the initial query show up for all subsequent table views.
It seems that the sectionNameKeyPath field is only invoked by the FetchedResultsController when there is a different # of results in the result set? The actual results are different - the Job names display correctly in the actual rows - but again, I don't think the section labels are faulting or asking the NSFetchedResultsController for the section labels correctly. I am using the following:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
int count = [[results_ sections] count];
if (count > section) {
id <NSFetchedResultsSectionInfo> sectionInfo = [[results_ sections] objectAtIndex:section];
return [sectionInfo name];
}
return nil;
}
where results_ is the NSFetchedResultsController that I am re building for each query.
Am I missing something? Is there a way to manually clear that Core Data cache so that it stops being so smart and, on every query, surely looks up the sectionNameKeyPath?
For what its worth, I unchecked the "Transient" option for the fields in the xcdatamodel but I'm getting the same results.
One final anomally from this is that when I create the first Job as Inactive (not the default startup view) - if I also then create an Active job ... the Inactive section label sticks to both. Furthermore, when I shutdown the application and start over ... the Inactive section label still shows up --- even though, on the title screen, I am displaying the Active Job which should be showing completely different label.
I can't but think this is a Core Data problem. It makes no sense that restarting the application is returning data so out of whack.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
根据 Marcus S. Zarra 的 评论,我将 cacheName 设置为 nil:
Per Marcus S. Zarra's comment, I set the cacheName to nil: