1.1 复用机制
在我们使用UITableView 和 UICollectionView时,通常会复用cell,当需要展示的数据条较多时,只创建较少数量的cell 对象,一般是屏幕可显示测Cell 数+ 1, 通过复用的方式来展示数据. 这种机制不会为每一条数据都创建一个Cell,所以可以节省内存,提升程序的效率和交互流畅性. 另外,在iOS 6以后,section中的Header 和Footer也能复用
复用会用到的API:
复用机制不正确的使用会给我们的程序带来很多问题
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString * CellIdentifier = @"UITableViewCell"; UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; // 偶数行 Cell 的 textLabel 的文字颜色为红色。 if (indexPath.row % 2 == 0) { [cell.textLabel setTextColor:[UIColor redColor]]; } } cell.textLabel.text = @"Title"; // 偶数行 Cell 的 detailTextLabel 显示 Detail 文字。 if (indexPath.row % 2 == 0) { cell.detailTextLabel.text = @"Detail"; } return cell; }
我们本来只是希望只有偶数行的textLabel的文字颜色为红色,并 且显示Detail文字,但是当你滑动TableView的时候发现不对了,有些奇数行的textLabel的文字颜色为红色,而且还显示了Detail文字. 这种情况的出现就是因为/复用/,如果刚好某一个cell 没有显式的设置它的属性,那么它这些属性就直接复用别的cell. 还有一个问题就是,对偶数行的cell 的textLabel的文字颜色设置放在了初始化一个cell的if代码块中,这样在复用cell的时候,因为cell != nil, 逻辑走不到这里,所以这样也会出现复用问题,所以我们将cell的颜色属性改变设置在cell != nil 的时候,放在cell复用的地方
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString * CellIdentifier = @"UITableViewCell"; UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; } cell.textLabel.text = @"Title"; if (indexPath.row % 2 == 0) { [cell.textLabel setTextColor:[UIColor redColor]]; cell.detailTextLabel.text = @"Detail"; } else { [cell.textLabel setTextColor:[UIColor blackColor]]; cell.detailTextLabel.text = nil; } return cell; }
2. 1控件重叠
在UITableViewCell的使用中,使用纯代码方式添加控件,当复用cell的时候,可能出现控件重叠现象.我们可能需要对cell中添加的控件进行清空,cell的复用不变,只是在新的cell加载前,都会对上一个cell的contentView贴的控件进行清空,代码如下
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *CellIdentifer = @"DiscoverHomeInnerTableViewCell"; DiscoverHomeInnerTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifer forIndexPath:indexPath]; //TODO 解决cell复用重叠问题 for (UIView *subview in [cell.contentView subviews]) { [subview removeFromSuperview]; } UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; //button相关设置 [cell.contentView addSubview:button]; UILabel *lab = [[UILabel alloc] init]; //lab相关设置 [cell.contentView addSubview:lab]; }
从上面分析得知,在复用cell的时候需要注意的问题点:
- 若要设置不同行数或者在某些条件下,不同的cell属性(包括样式,内容)时,要注意不能在cell 初始化内部中设定,要放在初始化的外部,同时用if 和else 显式的覆盖所有的可能性,对所有的可能性进行判断和设定属性;
本文的第一部分 ,有关"复用机制"的讨论,引用并参考了冰晨-简书