iOS开发之UI学习-UITableView的复用机制

    最近编写新功能的时候,偶然间发现有较少开发经验的开发人员对于表视图的单元格的复用问题并不是了解的很透彻,所以在此通过代码的形式快速的教给大家如何理解和运用单元格的复用问题。表视图是在开发中经常使用的控件,而且有时处理的内容量也是非常巨大的,这就需要考虑表视图的性能优化,而最基本的性能优化则是单元格的复用,正所谓基础打得好,才能飞得高,所以需要很好的理解单元格是如何复用的。


    在表视图显示的时候,会创建 (视图中可看的单元格个数+1)个单元格,一旦单元格因为滑动的而消失在我们的视野中的时候,消失的单元格就会进入缓存池(或叫复用池),当有新的单元格需要显示的时候,会先从缓存池中取可用的单元格,获取成功则使用获取到的单元格,获取失败则重新创建心的单元格,这就是整个的复用机制。但是如何进行复用,这里有两种方式:


第一种方式:

自己手动创建新的单元格

#import "ViewController.h"

#define width  [UIScreen mainScreen].bounds.size.width
#define height [UIScreen mainScreen].bounds.size.height

static NSString *identifying = @"标识";

@interface ViewController ()<UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, strong) UITableView *tableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //创建表视图
    /*
     UITableViewStylePlain     平铺类型
     UITableViewStyleGrouped   分组类型
     */
    _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, width, height) style:UITableViewStylePlain];
    //让当前控制器成为表视图的代理
    _tableView.delegate = self;
    _tableView.dataSource = self;
    [self.view addSubview:_tableView];
}

#pragma mark - UITableViewDelegate 代理方法
//设置cell的行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    return 100;
}

#pragma mark - UITableViewDataSource 数据源
//设置cell的个数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    
    return 20;
}

//设置cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    //1.根据标识去缓存池中去取cell
    UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:identifying];
    
    //2.根据是否取到了可用的cell来判断是否需要重新创建cell(手动创建新的单元格)
    if (cell == nil){
        
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifying];
    }
    //3.设置单元格的显示数据
    cell.textLabel.text = [NSString stringWithFormat:@"第%ld行",indexPath.row];
    
    //通过打印cell的地址,我们来查看是否复用了cell
    NSLog(@"address --- %p ----- 第%ld行",cell, indexPath.row);
    
    return cell;
}

@end

通过打印的地址我们可以看出复用:






第二种方式:

通过注册单元格类的方式,由表视图自己创建单元格

#import "ViewController.h"

#define width  [UIScreen mainScreen].bounds.size.width
#define height [UIScreen mainScreen].bounds.size.height

static NSString *identifying = @"标识";

@interface ViewController ()<UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, strong) UITableView *tableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //创建表视图
    /*
     UITableViewStylePlain     平铺类型
     UITableViewStyleGrouped   分组类型
     */
    _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, width, height) style:UITableViewStylePlain];
    //让当前控制器成为表视图的代理
    _tableView.delegate = self;
    _tableView.dataSource = self;
    [self.view addSubview:_tableView];
    
    //注册单元格的类型
    [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:identifying];
}

#pragma mark - UITableViewDelegate 代理方法
//设置cell的行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

    return 100;
}

#pragma mark - UITableViewDataSource 数据源
//设置cell的个数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    return 20;
}

//设置cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    //1.根据标识去缓存池中去取cell
    UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:identifying];

    //2.倘若根据ID标识来判断有没有对应的cell类型,当缓存池中没有可以复用的cell的时候,会根据注册的类型自动创建cell
    
    //3.设置单元格的显示数据
    cell.textLabel.text = [NSString stringWithFormat:@"第%ld行",indexPath.row];
    
    //通过打印cell的地址,我们来查看是否复用了cell
    NSLog(@"address --- %p ----- 第%ld行",cell, indexPath.row);
    
    return cell;
}

@end

通过打印的地址我们可以看出复用:



两种单元格的复用的方式存在着细微的差别,新手一般情况下会不太理解,但是只要仔细观看以上的代码,或者将代码直接粘贴到新创建的工程中去,然后运行,可以得出和我截图出的一样的结果。希望以上代码能够帮助对于表视图的单元格复用不太理解的开发人群。当然这里只是简单的讲解了一下单元格的重用机制,在实际的开发过程中,可能会因为不同的展示效果,需要合理的利用单元格的复用。

 

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
iOS 开发中,TableView 是一个非常重要的视图控件,用于展示大量数据。而 TableView 中的 HeaderView 和 FooterView 也是非常重要的组件,可以用于展示一些额外的信息或者操作按钮。在 TableView 中,我们可以通过注册重用标识符来复用 Cell,但是对于 HeaderView 和 FooterView 却没有提供类似的注册方法。本文将介绍如何在 TableView 中循环利用 HeaderView,并且还会介绍如何自定义 HeaderView。 ## 循环利用 TableView 中的 HeaderView 在 TableView 中,我们可以通过以下方法来设置 HeaderView: ``` - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 44)]; headerView.backgroundColor = [UIColor grayColor]; return headerView; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 44; } ``` 上面的代码中,我们通过实现 `tableView:viewForHeaderInSection:` 方法来设置 HeaderView 的内容和样式,通过实现 `tableView:heightForHeaderInSection:` 方法来设置 HeaderView 的高度。但是如果我们在 TableView 中有很多组数据,每次都创建一个新的 HeaderView 会非常消耗性能,因此我们需要对 HeaderView 进行循环利用。 循环利用 HeaderView 的实现方法非常简单,我们只需要在 TableView 的代理方法中通过 `dequeueReusableHeaderFooterViewWithIdentifier:` 方法来获取 HeaderView,如果获取到的 HeaderView 为 nil,就创建一个新的 HeaderView,否则就返回重用的 HeaderView。 ``` - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { static NSString *headerIdentifier = @"headerIdentifier"; UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerIdentifier]; if (!headerView) { headerView = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:headerIdentifier]; headerView.contentView.backgroundColor = [UIColor grayColor]; } return headerView; } ``` 上面的代码中,我们首先定义一个静态的重用标识符 `headerIdentifier`,然后通过 `dequeueReusableHeaderFooterViewWithIdentifier:` 方法获取重用的 HeaderView。如果获取到的 HeaderView 为 nil,我们就创建一个新的 HeaderView,并且设置它的重用标识符为 `headerIdentifier`。最后,我们设置 HeaderView 的背景颜色,并且返回 HeaderView。 ## 自定义 TableView 中的 HeaderView 除了循环利用 HeaderView,我们还可以自定义 HeaderView。自定义 HeaderView 的方法与自定义 Cell 的方法类似,我们需要在 XIB 或者代码中创建一个自定义的 HeaderView,然后在 TableView 的代理方法中返回它。 ### 在 XIB 中创建自定义 HeaderView 在 XIB 中创建自定义 HeaderView 的方法非常简单,我们只需要创建一个新的 XIB 文件,然后在 XIB 中添加一个 UIView,将它的 Class 设置为 UITableViewHeaderFooterView,接着就可以在 XIB 中自定义 HeaderView 的内容和样式了。 创建完成后,我们需要在代码中注册这个 XIB 文件,并且设置它的重用标识符。在 TableView 的初始化方法中,我们可以通过以下方法来注册 XIB 文件: ``` UINib *headerNib = [UINib nibWithNibName:@"HeaderView" bundle:nil]; [tableView registerNib:headerNib forHeaderFooterViewReuseIdentifier:@"headerIdentifier"]; ``` 上面的代码中,我们首先通过 `nibWithNibName:bundle:` 方法加载 XIB 文件,然后通过 `registerNib:forHeaderFooterViewReuseIdentifier:` 方法注册 XIB 文件,并且设置它的重用标识符为 `headerIdentifier`。 最后,在 TableView 的代理方法中,我们可以通过以下方法来获取自定义的 HeaderView: ``` - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { static NSString *headerIdentifier = @"headerIdentifier"; UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerIdentifier]; return headerView; } ``` ### 在代码中创建自定义 HeaderView 在代码中创建自定义 HeaderView 的方法也非常简单,我们只需要创建一个继承自 UITableViewHeaderFooterView 的类,然后在这个类中实现自定义 HeaderView 的内容和样式。 ``` @interface CustomHeaderView : UITableViewHeaderFooterView @property (nonatomic, strong) UILabel *titleLabel; @end @implementation CustomHeaderView - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithReuseIdentifier:reuseIdentifier]) { self.contentView.backgroundColor = [UIColor grayColor]; self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, self.contentView.bounds.size.width - 20, self.contentView.bounds.size.height)]; self.titleLabel.font = [UIFont systemFontOfSize:16]; self.titleLabel.textColor = [UIColor whiteColor]; [self.contentView addSubview:self.titleLabel]; } return self; } @end ``` 上面的代码中,我们创建了一个名为 `CustomHeaderView` 的类,继承自 UITableViewHeaderFooterView。在这个类的初始化方法中,我们设置了 HeaderView 的背景颜色,并且创建了一个 UILabel 来显示标题,最后将它添加到 HeaderView 的 contentView 上。 创建完成后,我们需要在代码中注册这个自定义 HeaderView,并且设置它的重用标识符。在 TableView 的初始化方法中,我们可以通过以下方法来注册自定义 HeaderView: ``` [tableView registerClass:[CustomHeaderView class] forHeaderFooterViewReuseIdentifier:@"headerIdentifier"]; ``` 上面的代码中,我们通过 `registerClass:forHeaderFooterViewReuseIdentifier:` 方法注册自定义 HeaderView,并且设置它的重用标识符为 `headerIdentifier`。 最后,在 TableView 的代理方法中,我们可以通过以下方法来获取自定义的 HeaderView: ``` - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { static NSString *headerIdentifier = @"headerIdentifier"; CustomHeaderView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerIdentifier]; headerView.titleLabel.text = [NSString stringWithFormat:@"Header %ld", section]; return headerView; } ``` 上面的代码中,我们首先定义一个静态的重用标识符 `headerIdentifier`,然后通过 `dequeueReusableHeaderFooterViewWithIdentifier:` 方法获取自定义的 HeaderView,并且设置它的标题为 `Header section`。最后,我们返回自定义的 HeaderView。 总结 在本文中,我们介绍了如何在 TableView 中循环利用 HeaderView,并且还介绍了如何自定义 HeaderView。循环利用 HeaderView 可以提高 TableView 的性能,自定义 HeaderView 可以让我们更加灵活地控制 HeaderView 的样式和内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值