Unheilig
Unheilig

Reputation: 16292

iOS: Add / Update UITableView Cell Row by Row

I have been struggling with this for a week and my head is about to explode.

Basically I use Prototype Cell, in CellWillAppear I did a little customizations like background color. Nothing fancy.

Due to this, my table view is always empty at start up (no cell) unless the array (data source) is filled with something. So what I did was in NumberOfRowsInSection:

return dataArray.count < 10? 10 : dataArray.count

I am doing this because I would like to see at least some empty cells when there is no data. Meaning it will show on start up at least 10 empty cells.

To add data to the cell, I call the delegate method in my tableviewcontroller each and every time to add one single entity in the data array (am doing this, because I think it would be faster than waiting until the whole array is filled then call [self.tableView reloadData];) and then refresh it by using reloadRowsAtIndexPaths. But it crashed every single time when it reached to index 10 (error: ... before update number of data was 10, but after update is 11).

What I really want is:

1.) prepare some data

2.) send it to uitableview controller and add it to an array there, instead of waiting and then sending a whole array to table view and refresh at once.

3.) reload just one row after the update (instead of using reloadData -> since I have different color of cell, the whole reload thing cause my table view flash madly).

The one thing I am doing to cell customization is in willDisplayCell: What I did there is to change the background color of the cell. Again, nothing fancy. But since there is no data at start up, no cell is ever visible (ui tablew with no cell at displayed at all), unless I did this

return dataArray.count < 10? 10 : dataArray.count;

just so there are at least 10 empty cells showing (WHY do I have to do the above just to display some customized empty cells beats me...).

Using reloadData is to refresh no problem, but since I am updating the data source array in table view every time data is ready instead of saving all prepared data to this array and send it over to table view to update by using reloadData, I would like to update row by row.

I kind of feel that the error comes from the fact that, if I add one item in the array and then call reloadRowsAtIndexPath, it will say "Ok, you had one item before, but after update there is 2! Inconsistency.."

I have already tried using [tableView beginUpdate]; and [tableView endUpdate]; Nothing has worked so far.....

So to sum up: how can I have different colors of cells showing even when the data array is empty on start up (just like the default ui table view with cells displaying completely even with no data) and update just one of the cells once a piece of data is ready instead of updating the whole ui table view with reloadData?

Many thanks in advance, please advise. Regards.

Upvotes: 2

Views: 4386

Answers (1)

rdelmar
rdelmar

Reputation: 104082

"how can I have different colors of cells showing even when the data array is empty"

Don't have an empty array, have a mutable array where all the members are initially empty strings, and replace those with your real data when you get it.

"update just one of the cells once a piece of data is ready"

Update your array with the new data, and then use reloadRowsAtIndexPaths:withRowAnimation: to update the table. If you want to see the table update row by row (slow enough to see), then put your data in a temporary array first, then add it one element at a time using performSelector:withObject:afterDelay:, calling reloadRowsAtIndexPaths:withRowAnimation: after each addition.

It's a little hard to tell exactly what you want, but here is an example of what I mean. This table displays 20 empty rows, all with different colors, for 2 seconds, then it replaces the empty strings in displayData with the strings in theData one by one at a rate of 10 per second.

@interface TableController ()
@property (strong,nonatomic) NSArray *theData;
@property (strong,nonatomic) NSMutableArray *displayData;
@end

@implementation TableController 


- (void)viewDidLoad {
    [super viewDidLoad];
    self.displayData = [@[@"",@"",@"",@"",@"",@"",@"",@"",@"",@"",@"",@"",@"",@"",@"",@"",@"",@"",@"",@""] mutableCopy];
    self.theData = @[@"One",@"Two",@"Three",@"Four",@"Five",@"Six",@"Seven",@"Eight",@"Nine",@"ten",@"Black",@"Brown",@"Red",@"Orange",@"Yellow",@"Green",@"Blue",@"Violet",@"Gray",@"White"];
    [self.tableView reloadData];
    [self performSelector:@selector(addData) withObject:nil afterDelay:2];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.displayData.count;
}

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    UIColor *cellTint = [UIColor colorWithHue:indexPath.row * .05 saturation:1.0 brightness:1.0 alpha:1.0];
    cell.backgroundColor = cellTint;
}

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    cell.textLabel.text = self.displayData[indexPath.row];
    return cell;
}

-(void)addData {
    static int i = 0;
    [self.displayData replaceObjectAtIndex:i withObject:self.theData[i]];
    [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
    i++;
    if (i < self.displayData.count) [self performSelector:@selector(addData) withObject:nil afterDelay:.1];
}

If you don't want any delay between row updates, and you want to make it work when displayArray has a different number of rows that theData, this version of addData should work:

-(void)addData {
    static int i = 0;
    if (i < self.displayData.count && i< self.theData.count) {
        [self.displayData replaceObjectAtIndex:i withObject:self.theData[i]];
        [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
        i++;
        [self addData];
    }else if (i >= self.displayData.count && i< self.theData.count) {
        [self.displayData addObject:self.theData[i]];
        [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
        i++;
        [self addData];
    }
}

Upvotes: 6

Related Questions