NSFetchedResultsController 在使用“!=”时会创建额外的空行谓词
我有一个 UITableViewController,它由 NSFetchedResultsController 填充。我的 CoreData 实体有一个名为“submitter_id”的属性。根据我的控制器的初始化方式,我想获取与给定的提交者 ID 匹配或不匹配所述提交者 ID 的记录。 “匹配”的情况工作正常,但我在“不匹配”的情况下遇到麻烦。我的 sqlite 数据库是正确的,但我在 TableView 中得到额外的空行。
在下面的输出中,我从 Core Data 中获取了正确的 3 条记录,但随后 NSFetchedResultsController(或其他人)向我的 TableView 添加了 34 个空行。注意:空行的数量遵循一种模式,这可能是一个线索:如果我删除应用程序并从头开始,我首先会得到 17 个空行 + 3 个好的空行。当我第二次运行它时,我得到 34 个空行 + 3 个好行。从那时起,它就稳定在 34 个空行。有趣的是,我的测试数据集中有 17 条记录。
2011-03-25 15:35:17.256 test[54095:207] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZDELETED, t0.ZDESCRIPTION, t0.ZITEMID, t0.ZICON, t0.ZAVG, t0.ZNAME, t0.ZCREATIONDATE, t0.ZIMAGE, t0.ZSUBMITTERID, t0.ZUSER FROM ZITEM t0 WHERE t0.ZSUBMITTERID <> ? ORDER BY t0.ZNAME DESC
2011-03-25 15:35:17.257 test[54095:207] CoreData: details: SQLite bind[0] = 32
2011-03-25 15:35:17.258 test[54095:207] CoreData: annotation: sql connection fetch time: 0.0017s
2011-03-25 15:35:17.258 test[54095:207] CoreData: annotation: fetch using <NSSQLiteStatement: 0x5f920f0> returned 3 rows with values: (
"Plastic ballpoint",
"Walmart readers",
Blue
)
2011-03-25 15:35:17.263 test[54095:207] CoreData: annotation: total fetch execution time: 0.0071s for 3 rows.
2011-03-25 15:35:17.264 test[54095:207] numberOfSectionsInTableView: 1
2011-03-25 15:35:17.264 test[54095:207] numberOfRowsInSection 0: 37
2011-03-25 15:35:17.265 test[54095:207] indexPath 0
2011-03-25 15:35:17.268 test[54095:207] name: pen
2011-03-25 15:35:17.268 test[54095:207] indexPath 1
2011-03-25 15:35:17.269 test[54095:207] name: glasses
2011-03-25 15:35:17.269 test[54095:207] indexPath 2
2011-03-25 15:35:17.270 test[54095:207] name: checkbook
2011-03-25 15:35:17.270 test[54095:207] indexPath 3
2011-03-25 15:35:17.272 test[54095:207] name: (null)
2011-03-25 15:35:17.273 test[54095:207] indexPath 4
2011-03-25 15:35:17.275 test[54095:207] name: (null)
2011-03-25 15:35:17.275 test[54095:207] indexPath 5
2011-03-25 15:35:17.275 test[54095:207] name: (null)
2011-03-25 15:35:17.278 test[54095:207] indexPath 6
2011-03-25 15:35:17.279 test[54095:207] name: (null)
2011-03-25 15:35:17.279 test[54095:207] indexPath 7
2011-03-25 15:35:17.280 test[54095:207] name: (null)
2011-03-25 15:35:17.281 test[54095:207] indexPath 8
2011-03-25 15:35:17.281 test[54095:207] name: (null)
这是我设置 NSFetchedResultsController 的代码:
- (BOOL) setupFRC
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:self.managedObjectContext];
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:NO]];
NSPredicate *p1;
if (self.listType == MY_ITEMS_LIST) {
p1 = [NSPredicate predicateWithFormat:@"submitterID == %qu", appDelegate.user.userID];
}
else {
p1 = [NSPredicate predicateWithFormat:@"submitterID != %qu", appDelegate.user.userID];
}
request.predicate = p1;
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc]
initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
frc.delegate = self;
self.fetchedResultsController = frc;
[frc release];
[request release];
return YES;
}
- (void)performFetchForTableView
{
NSError *error = nil;
[self.fetchedResultsController performFetch:&error];
if (error) {
NSLog(@"[CoreDataTableViewController performFetchForTableView:] %@ (%@)", [error localizedDescription], [error localizedFailureReason]);
}
[self.tableView reloadData];
}
这是我格式化单元格的地方:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForManagedObject:(NSManagedObject *)managedObject
{
static NSString *CellIdentifier;
if (self.listType == MY_ITEMS_LIST) {
CellIdentifier = @"RSMyItemCell";
}
else {
CellIdentifier = @"RSTBDItemCell";
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
CDItem *item = (CDItem *)managedObject;
cell.textLabel.text = item.name;
cell.detailTextLabel.text = item.description;
NSLog(@"name: %@",item.name);
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
NSInteger n = [sectionInfo numberOfObjects];
NSLog(@"numberOfRowsInSection %d: %d",section,n);
return n;
}
我确信我遗漏了一些东西,但我对如何进一步调试它感到困惑。有人以前见过这个吗?如果您想查看任何其他代码片段,请告诉我。
谢谢!
斯图
I have a UITableViewController which is populated by an NSFetchedResultsController. My CoreData entity has an attribute called "submitter_id". Depending on how my controller is initialized, I want to fetch records which match a given submitter_id or which DON'T match said submitter_id. The "does match" case works fine, but I'm having trouble with the "doesn't match" case. My sqlite db is correct, but I get extra empty rows in the TableView.
In the following output, I get the correct 3 records from Core Data, but then the NSFetchedResultsController (or somebody) adds 34 more empty rows to my TableView. Note: the number of empty rows follows a pattern which may be a clue: If I delete the app and start from scratch, I first get 17 empty rows + 3 good ones. When I run it a second time, I get 34 empty rows + 3 good ones. From then on, it's stable at 34 empty rows. Interestingly, I have 17 records in my test dataset.
2011-03-25 15:35:17.256 test[54095:207] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZDELETED, t0.ZDESCRIPTION, t0.ZITEMID, t0.ZICON, t0.ZAVG, t0.ZNAME, t0.ZCREATIONDATE, t0.ZIMAGE, t0.ZSUBMITTERID, t0.ZUSER FROM ZITEM t0 WHERE t0.ZSUBMITTERID <> ? ORDER BY t0.ZNAME DESC
2011-03-25 15:35:17.257 test[54095:207] CoreData: details: SQLite bind[0] = 32
2011-03-25 15:35:17.258 test[54095:207] CoreData: annotation: sql connection fetch time: 0.0017s
2011-03-25 15:35:17.258 test[54095:207] CoreData: annotation: fetch using <NSSQLiteStatement: 0x5f920f0> returned 3 rows with values: (
"Plastic ballpoint",
"Walmart readers",
Blue
)
2011-03-25 15:35:17.263 test[54095:207] CoreData: annotation: total fetch execution time: 0.0071s for 3 rows.
2011-03-25 15:35:17.264 test[54095:207] numberOfSectionsInTableView: 1
2011-03-25 15:35:17.264 test[54095:207] numberOfRowsInSection 0: 37
2011-03-25 15:35:17.265 test[54095:207] indexPath 0
2011-03-25 15:35:17.268 test[54095:207] name: pen
2011-03-25 15:35:17.268 test[54095:207] indexPath 1
2011-03-25 15:35:17.269 test[54095:207] name: glasses
2011-03-25 15:35:17.269 test[54095:207] indexPath 2
2011-03-25 15:35:17.270 test[54095:207] name: checkbook
2011-03-25 15:35:17.270 test[54095:207] indexPath 3
2011-03-25 15:35:17.272 test[54095:207] name: (null)
2011-03-25 15:35:17.273 test[54095:207] indexPath 4
2011-03-25 15:35:17.275 test[54095:207] name: (null)
2011-03-25 15:35:17.275 test[54095:207] indexPath 5
2011-03-25 15:35:17.275 test[54095:207] name: (null)
2011-03-25 15:35:17.278 test[54095:207] indexPath 6
2011-03-25 15:35:17.279 test[54095:207] name: (null)
2011-03-25 15:35:17.279 test[54095:207] indexPath 7
2011-03-25 15:35:17.280 test[54095:207] name: (null)
2011-03-25 15:35:17.281 test[54095:207] indexPath 8
2011-03-25 15:35:17.281 test[54095:207] name: (null)
Here's the code where I set up the NSFetchedResultsController:
- (BOOL) setupFRC
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:self.managedObjectContext];
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:NO]];
NSPredicate *p1;
if (self.listType == MY_ITEMS_LIST) {
p1 = [NSPredicate predicateWithFormat:@"submitterID == %qu", appDelegate.user.userID];
}
else {
p1 = [NSPredicate predicateWithFormat:@"submitterID != %qu", appDelegate.user.userID];
}
request.predicate = p1;
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc]
initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
frc.delegate = self;
self.fetchedResultsController = frc;
[frc release];
[request release];
return YES;
}
- (void)performFetchForTableView
{
NSError *error = nil;
[self.fetchedResultsController performFetch:&error];
if (error) {
NSLog(@"[CoreDataTableViewController performFetchForTableView:] %@ (%@)", [error localizedDescription], [error localizedFailureReason]);
}
[self.tableView reloadData];
}
And here's where I format the cells:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForManagedObject:(NSManagedObject *)managedObject
{
static NSString *CellIdentifier;
if (self.listType == MY_ITEMS_LIST) {
CellIdentifier = @"RSMyItemCell";
}
else {
CellIdentifier = @"RSTBDItemCell";
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
CDItem *item = (CDItem *)managedObject;
cell.textLabel.text = item.name;
cell.detailTextLabel.text = item.description;
NSLog(@"name: %@",item.name);
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
NSInteger n = [sectionInfo numberOfObjects];
NSLog(@"numberOfRowsInSection %d: %d",section,n);
return n;
}
I'm sure I'm missing something, but I'm stumped on how to debug it further. Anyone seen this before? If you'd like to see any other code snippets, let me know.
Thanks!
stu
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
有时只需要清醒的头脑。周末回来后,我发现了问题。以下是发生的情况供您参考:
在应用程序启动时,我使用从服务器下载的项目列表更新 CoreData DB。在尝试添加给定项目之前,我会检查 CoreData 中是否已存在该项目。错误是我
在执行存在检查之前打电话。这导致创建的实体没有相应的管理对象。即使 CoreData 将正确的数据集返回给 NSFetchedResultsController,控制器也必须使用实体计数来确定
[sectionInfo numberOfObjects]
;无论如何,将
insertNewObjectForEntityForName
调用移至“不存在”子句(发生addObject
的位置)内可以解决问题。谢谢,
斯图
Sometimes a clear head is all that's needed. Coming back after the weekend, I saw the problem. For your reference, here's what happened:
At app startup, I update the CoreData DB with a list of items downloaded from a server. I check to see if a given item already exists in CoreData before attempting to add it. The bug was that I was calling
before performing my existence check. This caused an entity to be created with no corresponding managed object. Even though CoreData returns the correct dataset to the NSFetchedResultsController, the controller must use an entity count to determine
[sectionInfo numberOfObjects]
;In any case, moving the
insertNewObjectForEntityForName
call inside the "doesn't exist" clause (whereaddObject
happens) fixed the problem.Thanks,
stu