1

我真的很挣扎,希望有人能提供帮助。

我正在使用 Core Data 并正在使用 fetchedResultsController 填充 TableView。对于我使用自定义的单元格类型。选择一个与详细视图相连接的单元格后,我更改了其中一个字段并点击保存,这会将我带回表格视图。唯一的问题是旧字段文本仍然存在,而新文本与其重叠。

我的 tableviewcontroller.m 具有以下单元格代码:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {

        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

        [self configureCell:cell atIndexPath:indexPath];
    }
    else {

        // Cells all appear blank if I don't include the following line
        [self configureCell:cell atIndexPath:indexPath];

        Games *game = [self.fetchedResultsController objectAtIndexPath:indexPath];

        UILabel *nwOpp = (UILabel *)[cell.contentView viewWithTag:401];
        NSLog(@"nwOpp:%@", nwOpp.text);
        nwOpp.text = [NSString stringWithFormat:@"%@", game.opponents.name];

        UILabel *nwDate = (UILabel *)[cell.contentView viewWithTag:501];
        NSLog(@"Date:%@", nwDate.text);
        nwDate.text = [NSString stringWithFormat:@"%@  -  %@" , [dateFormatter stringFromDate: game.date] , game.location];

        UIImageView *nwImg2 = (UIImageView *)[cell.contentView viewWithTag:201];
        nwImg2.image = game.opponents.image;
    }

    return cell;
}

    - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {

    Games *game = [self.fetchedResultsController objectAtIndexPath:indexPath];

    CGRect imageFrame = CGRectMake(70, 2, 20, 20);
    UIImageView *customImage = [[UIImageView alloc] initWithFrame:imageFrame];
    [customImage setContentMode:UIViewContentModeScaleAspectFill];
    customImage.clipsToBounds = YES;
    customImage.image = game.teams.image;
    customImage.tag = 101;
    [cell.contentView addSubview:customImage];

    CGRect imageFrame2 = CGRectMake(230, 2, 20, 20);
    UIImageView *customImage2 = [[UIImageView alloc] initWithFrame:imageFrame2];
    [customImage2 setContentMode:UIViewContentModeScaleAspectFill];
    customImage2.clipsToBounds = YES;
    customImage2.image = game.opponents.image;
    customImage2.tag = 201;
    [cell.contentView addSubview:customImage2];

    CGRect teamFrame = CGRectMake(0, 18, 140, 24);
    UILabel *teamLabel = [[UILabel alloc] initWithFrame:teamFrame];
    teamLabel.font = [UIFont boldSystemFontOfSize:14];
    teamLabel.text = [NSString stringWithFormat:@"%@", game.teams.name];
    teamLabel.textAlignment = NSTextAlignmentCenter;
    teamLabel.tag = 301;
    [cell.contentView addSubview:teamLabel];

    CGRect versusFrame = CGRectMake(140, 18, 20, 24);
    UILabel *versusLabel = [[UILabel alloc] initWithFrame:versusFrame];
    versusLabel.font = [UIFont boldSystemFontOfSize:16];
    versusLabel.text = @"vs";
    versusLabel.textAlignment= NSTextAlignmentCenter;
    [cell.contentView addSubview:versusLabel];

    CGRect oppFrame = CGRectMake(160, 18, 140, 24);
    UILabel *oppLabel = [[UILabel alloc] initWithFrame:oppFrame];
    oppLabel.font = [UIFont boldSystemFontOfSize:14];
    oppLabel.text = [NSString stringWithFormat:@"%@", game.opponents.name];
    oppLabel.textAlignment = NSTextAlignmentCenter;
    oppLabel.tag = 401;
    [cell.contentView addSubview:oppLabel];

    CGRect dateFrame = CGRectMake(10, 40, 300, 12);
    UILabel *dateLabel = [[UILabel alloc] initWithFrame:dateFrame];
    dateLabel.font = [UIFont systemFontOfSize:10];
    dateLabel.text = [NSString stringWithFormat:@"%@  -  %@" , [dateFormatter stringFromDate: game.date] , game.location];
    dateLabel.textAlignment = NSTextAlignmentCenter;
    dateLabel.tag = 501;
    [cell.contentView addSubview:dateLabel];

}

我正在使用委托方法来保存数据更改:

    -(void)EditGameViewControllerDidSave {

    NSError *error = nil;
    NSManagedObjectContext *context = self.managedObjectContext;
    if (![context save:&error]) {
        NSLog(@"Error! %@", error);
    }

    [self.navigationController popViewControllerAnimated:YES];

    [self.tableView reloadData];
}

FetchedResultsController 更改:

    -(void) controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}

-(void) controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
}

-(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.tableView;

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }

}
4

1 回答 1

2

The problem is that you are misusing the boilerplate configureCell method.

If you look at Apple's template code you will notice that it is used to configure a fully created cell, i.e. populate it with data.

The cell creation can be largely omitted when using storyboard. With storyboard, typically there is no need to create stuff in if (cell==nil) {...}. Of course you can still do it in code, if not in the if block also in a separate method, if you prefer. I would recommend to call this method createCell though, not configureCell.

In configureCell: you can then put in your data - what you are already doing outside the if block in cellForRowAtIndexPath: That is actually the stuff that goes into configureCell.

The way you are doing it now, you are creating new labels in the NSFetchedResultsControllerDelegate callback when the data changes. You are calling configureCell in case of NSFetchedResultsChangeUpdate (indeed exactly what is happening when changing an attribute), but configureCell creates new views and adds them to the cell.

Therefore, simply move your cell creation code out of configureCell and your code populating the cell with data into configureCell and you should be fine.

于 2013-08-21T23:47:51.587 回答