多类型UITableViewCell重用的正确姿态

对于iOS开发者,UITableViewCell的重用是最基本的技能,初学者都应该掌握的。对于它的原理我就不在此啰嗦了,这里我重点说下,如何以正确的姿态来重用多类型的UITableViewCell,正确重用cell不仅仅要重用cell视图,还需要好好重用cell的子视图。你是否做到了呢?


单一类型cell重用

对于简单单一cell的tableView来讲,它的重用我们大多会在代理方法里这样写:

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//设置重用标识符
static NSString * Identifier = @"MineCell";
//通过Identifier取到cell
MineTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier];
//若cell不存在,在进行创建
if (!cell) {
    cell =[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: Identifier];
}
    //用set方法取到对应的model对cell赋值
    [cell cellModel:self.cellModelArr[indexPath.row]];
    return cell;
}

或者使用需要注册cell的写法:

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//设置重用标识符
static NSString *Identifier = @"MineCell";
 MineTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier forIndexPath:indexPath];
  //用set方法取到对应的model对cell赋值
  [cell setCellModel:self.cellModelArr[indexPath.row]];
  return cell;
}

上面的两种写法都很简单,由于是单一类型的cell重用,不会涉及到子视图的重用,所以没什么可讲的。

多类型cell重用

在很多情况下,UITableView并不是单一的一种cell,而会包含多种cell,每种cell类型样式布局都有明显区别。这样来我们就不能用上面单一的cell重用方式了。 对于多类型cell你当然可以对每个类型的cell创建对应的.h .m文件,并在使用时引入该 cell的头文件即可。但可能是出于偷懒,我更习惯统一处理这些cell。把这些cell都写在一个.h .m文件内,通过对不同类型cell设置对应对cellStyle枚举状态来辨别他们,这样以来,一个文件就足够了。
下面就重点说下单文件下多类型cell的重用。主要代码如下:

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

static NSString * MineCellIdentifier = @"MineCellIdentifier";

 //通过注册的cell获取MineTableViewCell
 MineTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MineCellIdentifier forIndexPath:indexPath];

    //根据不同row或者也可以根据model内容来区分cellStyle
    if (indexPath.row == 0) {
        //通过setMineCellStyle:方法对cell就行类型赋值,我们会在 setMineCellStyle:方法里对cell就行布局等定制化处理。
        cell.mineCellStyle = MineTableViewCellStyleOne;
    }else
    {
        cell.mineCellStyle = MineTableViewCellStyleTow;
    }
    //用set方法取到对应的model对cell赋值
    [cell setCellModel:self.cellModelArr[indexPath.row]];
    return cell;
}

我们一般会在MineTableViewCell.h里定义类似MineTableViewCellStyle的枚举类型,并实现mineCellStyle属性,这样就可以在对应的tableView代理方法里通过setMineCellStyle:方法来针对不同cellStyle布局了。setMineCellStyle:方法内部实现大概如下:

- (void)setMineCellStyle:(MineTableViewCellStyle)mineCellStyle
{
    _mineCellStyle = mineCellStyle;
   //为了避免cell重用引起的子视图错乱,我们会先把cell的子视图给全不移除,下面会在对应的cellStyle内重新创建并添加到cell的contentView内。
    for (UIView *view in self.contentView.subviews) {
        [view removeFromSuperview];
    }
    //对不同的类型进行针对性的布局绘制操作
    switch (mineCellStyle) {
        case MineTableViewCellStyleOne:
        {
            //这里省略了布局约束的代码
            NSArray *viewArray = @[self.bankNumTitleLb, self.bankNumLb];
            for (UIView *view in viewArray) {
                [self.contentView addSubview:view];
            }
           //进行布局操作(此处省略不是本文重点)
        }
            break;
        case MineTableViewCellStyleTow:
        {
            //这里省略了布局约束的代码
            NSArray *viewArray = @[self.phoneNumTitleLb, self.phoneNumTextField];
            for (UIView *view in viewArray) {
                [self.contentView addSubview:view];
            }
             //进行布局操作(此处省略不是本文重点)
        }
            break;
        case MineTableViewCellStyleDefault:
        {
            //这里省略了布局约束的代码
            NSArray *viewArray = @[self.verificationCodeTitleLb,
            self.phoneNumTextField,self.verificationCodeButton];
            for (UIView *view in viewArray) {
                [self.contentView addSubview:view];
            }
           //进行布局操作(此处省略不是本文重点)
        }
            break;
    }
}

到这里也许你觉得一切都没什么问题。但有经验的开发者可能已经看出来问题所在。问题出在setMineCellStyle:方法里的这句代码:

    for (UIView *view in self.contentView.subviews) {
        [view removeFromSuperview];
    }

这句代码很简单,就是前面说到为了解决cell重用时会出现子视图的重用。可是"解决"了子视图的重用问题,那么新问题来了,每次都把子视图移除,重新创建既消耗内存还占用时间,严重会出现滑动出现卡顿现象,而且都删除了重建还能叫重用吗?最多是只是留了个cell的'壳',里面的'肉'可都是新建的啊。

因此:在通过设置多种cell枚举类型来实现多样式cell布局时,要先判断当前重用的cellStyle 和 需要设置的cellStyle是否一致,不一致时,才需要重新布局绘制。

修改后的主要代码如下:

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString * MineCellIdentifier = @"MineCellIdentifier";
    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:MineCellOneIdentifier forIndexPath:indexPath];
    //获取当前重用cell的类型cellStyle
    MineCellStyle cellStyle = cell.mineCellStyle;
    switch (indexPath.section) {
        case 0:
        {
            //如果当前重用的cellStyle 和 需要设置的cellStyle不一致时,才进行类型重制!
            if (cellStyle !=  MineTableViewCellStyleOne) {
                cell.mineCellStyle = MineTableViewCellStyleOne;
            }
             [cell setCellModel:self.cellModelArr[indexPath.row]];
        }
            break;
        case 1:
        {
            switch (indexPath.row) {
                case 0:
                {
                    if (cellStyle !=  MineTableViewCellStyleTow) {
                        cell.mineCellStyle = MineTableViewCellStyleTow;
                    }
                    [cell setCellModel:self.cellModelArr[indexPath.row]];
                }
                    break;
                case 1:
                {
                    if (cellStyle !=  MineTableViewCellStyleThree) {
                        cell.mineCellStyle = MineTableViewCellStyleThree;
                    }
                    [cell setCellModel:self.cellModelArr[indexPath.row]];
                }
                    break;
            }
        }
            break;
    }
    return cell;
}

这样以来即实现了单文件下实现多cell类型的功能,又完美的解决了多cell的重用及性能问题,如有疏漏不足之处多多指出。

你可能感兴趣的:(多类型UITableViewCell重用的正确姿态)