开发者

NSFetchedResultsController creates extra empty rows when using "!=" predicate

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 NSFetchedRes开发者_Go百科ultsController:

   - (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


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

[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:]

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 (where addObject happens) fixed the problem.

Thanks,

stu

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜