【问题标题】:iOS: Add / Update UITableView Cell Row by RowiOS:逐行添加/更新 UITableView 单元格
【发布时间】:2013-06-06 22:01:21
【问题描述】:

我已经为此苦苦挣扎了一个星期,我的头快要爆炸了。

基本上我使用 Prototype Cell,在 CellWillAppear 中我做了一些自定义,比如背景颜色。没有什么花哨。

因此,我的表格视图在启动时总是空的(没有单元格),除非数组(数据源)被填充了一些东西。所以我所做的是在 NumberOfRowsInSection 中:

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

我这样做是因为我希望在没有数据时至少看到一些空单元格。 这意味着它将在启动时显示至少 10 个空单元格。

为了向单元格添加数据,我每次都在我的 tableviewcontroller 中调用委托方法以在数据数组中添加一个实体(正在这样做,因为我认为这比等到整个数组完成填充然后调用 [self.tableView reloadData];) 然后使用 reloadRowsAtIndexPaths 刷新它。但是每次到达索引10时它都会崩溃(错误:...更新前数据数为10,但更新后为11)。

我真正想要的是:

1.) 准备一些数据

2.) 将其发送到 uitableview 控制器并将其添加到那里的数组中,而不是等待然后将整个数组发送到表视图并立即刷新。

3.) 更新后只重新加载一行(而不是使用 reloadData -> 因为我有不同颜色的单元格,整个重新加载的事情导致我的表格视图疯狂闪烁)。

我对单元格自定义所做的一件事是在 willDisplayCell 中: 我在那里所做的是更改单元格的背景颜色。再一次,没有什么花哨的。 但是由于在启动时没有数据,所以没有单元格是可见的(ui tablew,根本没有显示单元格),除非我这样做

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

至少显示了 10 个空单元格(为什么我必须执行上述操作只是为了显示一些自定义的空单元格击败我......)。

使用reloadData刷新是没有问题的,但是由于我每次数据准备好时都在表视图中更新数据源数组,而不是将所有准备好的数据保存到该数组中并通过使用reloadData将其发送到表视图进行更新,我想逐行更新。

我感觉错误来自这样一个事实,如果我在数组中添加一项,然后调用 reloadRowsAtIndexPath,它会说“好的,你之前有一项,但更新后有 2 个!不一致。 。”

我已经尝试过使用[tableView beginUpdate]; and [tableView endUpdate]; 到目前为止没有任何效果.....

总结一下:即使数据数组在启动时为空,我如何才能显示不同颜色的单元格(就像默认的 ui 表格视图,即使没有数据也可以完全显示单元格)并只更新其中一个一条数据准备好后的单元格,而不是使用 reloadData 更新整个 ui 表视图?

提前多谢,请指教。问候。

【问题讨论】:

  • 你能把你的问题改得更专注吗?最后一段似乎说明了最大的问题。另一方面对于异步图像加载:bit.ly/112chSV UITableView 是一个严肃的野兽,你应该阅读几个教程以在一定程度上理解它。
  • 不能用UITableView- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation方法吗?更多信息在这里:developer.apple.com/library/ios/#documentation/uikit/reference/…

标签: ios uitableview


【解决方案1】:

“即使数据数组为空,我如何才能显示不同颜色的单元格”

不要有一个空数组,有一个可变数组,其中所有成员最初都是空字符串,并在获得时将其替换为您的真实数据。

“一旦数据准备好,只更新一个单元格”

使用新数据更新您的数组,然后使用 reloadRowsAtIndexPaths:withRowAnimation: 更新表格。如果您想逐行查看表更新(足够慢以查看),则先将数据放入临时数组中,然后使用 performSelector:withObject:afterDelay: 一次添加一个元素,调用 reloadRowsAtIndexPaths:withRowAnimation: after每次添加。

确切地说出你想要什么有点困难,但这里有一个例子来说明我的意思。此表显示 20 个空行,全部用不同的颜色显示 2 秒,然后以每秒 10 个的速率将 displayData 中的空字符串一一替换为 theData 中的字符串。

@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];
}

如果您不希望行更新之间有任何延迟,并且希望在 displayArray 的行数与 theData 不同时使其工作,那么这个版本的 addData 应该可以工作:

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

【讨论】:

  • 您好,感谢回复和代码。从您的代码中我可以看到,鉴于需要延迟,表视图通常存在同步问题?我也尝试过使用虚拟单元格,它有效,但是当使用 reloadRowsAtIndexPaths 时另一个数组(self.theData)增长超过 20 时,就会出现问题。换句话说,使用 reloadRowsAtIndexPaths 不会产生任何问题,除非 self.theData 数组的计数大于虚拟数组。
  • @Unheilig,我并不是要暗示任何同步问题,我以为您想加载单元格的速度足够慢以查看。延迟纯粹是出于视觉目的。至于第二个问题,您只需要检查您是否在虚拟数组的最后一个索引处,如果是,则从 theData 添加值而不是替换空字符串。
  • 我明白了。我的意思是,如果 self.theData 数组增长超过 20,使用 reloadRowAtIndexPath 会导致任何问题吗?我问是因为这正是我使用 realodRowAtIndexPath 的问题。错误类似于“NSInconsistency Error, .... table view cells before update (rows: 20) but after update (rows: 21)....”谢谢。
  • @Unheilig,对不起,我不太明白你的问题。如果要添加新行,超出“虚拟”行的数量,则需要使用 insertRowsAtIndexPaths:withRowAnimation: 而不是 reloadRowsAtIndexPaths:。请记住,您需要先更新数组,然后调用该方法。
  • @Unheilig,我已经更新了我的答案,以使其在两个数组具有不同计数时起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-17
  • 2012-04-10
相关资源
最近更新 更多