質問

I am really struggling with this and am hoping someone can help.

I am using Core Data and am filling a TableView using a fetchedResultsController. For the cell type I am using Custom. After selecting a cell which segues to a detail view I change one of the fields and hit Save which takes me back to the tableview. Only problem is the old field text is still there and the new text is overlapping it.

My tableviewcontroller.m has the following code for the cell:

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

}

I am using a delegate method to save the data change:

    -(void)EditGameViewControllerDidSave {

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

    [self.navigationController popViewControllerAnimated:YES];

    [self.tableView reloadData];
}

FetchedResultsController Changes:

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

}
役に立ちましたか?

解決

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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top