iOS cell的复用以及自定义cell

自定义cell以及cell复用的内容

前言

cell是我们开发中的一个重要的控件,下面来讲解一下这个内容

cell的复用原理

cell的复用是UITableView的最核心的内容,这里解释一下他的一个复用原理:

初始化的时候他会先创建cell的缓存字典 和 section的缓存array,以及一个用于存放复用cell的mutableSet(可变的集合)。并且它会去创建显示的(n+1)个cell,其他都是从中取出来重用。

当有cell滑出屏幕时,会将其放入到一个set中(相当于一个重用池),当UITableView要求返回cell的时候,datasource会先在集合中查找是否有闲置的cell,若有则会将数据配置到这个cell中,并将cell返回给UITabelView。 这大大减少了内存的开销。

因为我在滚动的过程中会出现一个将cell滚出屏幕外的时候,这时候如果我们一直创建cell的话,如果cell太多了就会出现一个内存开销过多的一个问题。所以我们要采用这个复用的方式来提高内存利用率。

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

cell的复用的两种不同方式

接下来讲一下·cell的两种复用方式,主要分成注册和非注册两种方式。

注册

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStyleGrouped];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    self.ary = @[@"头像", @"名字", @"微信号"];
    [self.view addSubview:_tableView];
    [self.tableView registerClass:[cell02 class] forCellReuseIdentifier:@"cell"]; //使用代码自定义cell
    // Do any additional setup after loading the view.
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    cell02* cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
    return cell;
}

非注册

- (void)viewDidLoad {
    [super viewDidLoad];
    _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style: UITableViewStyleGrouped];
    //设置两个代理
    _tableView.delegate = self;
    _tableView.dataSource = self;
    [self.view addSubview:_tableView];
    // Do any additional setup after loading the view.
}
-(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString* cellStr = @"cell";
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:cellStr];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellStr];
    }
    return cell;
    

这两种方式都是可以实现复用的,两者有部分的区别,这里引用一段学长博客的话:

上述代码的区别在于注册方法需要提前对我们要使用的cell类进行注册,如此一来就不需要在后续过程中对我们的单元格进行判空。
这是因为我们的注册方法:

  • (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier API_AVAILABLE(ios(6.0));
    在调用过程中会自动返回一个单元格实例,如此一来我们就避免了判空操作

区别2:

引用的方法不同

  • - (nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
  • (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);

前者用于非注册的方式,后者用于注册的方式中。在写代码的时候注意一一对应。

自定义cell的实现

我们首先要实现自定义cell需要实现两个协议:

UITableViewDelegateUITableViewDataSource

前者的主要用于实现显示单元格,设置单元格的行高和对于制定的单元格的操作设置头视图和尾视图

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section API_AVAILABLE(ios(6.0));
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section API_AVAILABLE(ios(6.0));
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath API_AVAILABLE(ios(6.0));
- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section API_AVAILABLE(ios(6.0));
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section API_AVAILABLE(ios(6.0));
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;

后者主要用于设置UITableView的section和row的数量

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;

// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)

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

我们自定义cell先要创建一个类继承UITableViewCell

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN
@interface myCustomCell : UITableViewCell  //在这里设置我们自己需要的一些UI控件
@property (nonatomic, strong) UIButton* btn;
@property (nonatomic, strong) UILabel* label1;
@property (nonatomic, strong) UILabel* label2;
@property (nonatomic, strong) UIImageView* imageView01;
@end

NS_ASSUME_NONNULL_END

然后需要重写一个方法- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier

-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    if ([self.reuseIdentifier isEqualToString:@"picture"]) {
        _label1 = [[UILabel alloc] init];
        _label1.textColor = UIColor.blackColor;
        _label1.font = [UIFont systemFontOfSize:17];
        [self.contentView addSubview:_label1];
        
        _label2 = [[UILabel alloc] init];
        _label2.textColor = UIColor.grayColor;
        _label2.font = [UIFont systemFontOfSize:10];
        [self.contentView addSubview:_label2];
        
        _imageView01 = [[UIImageView alloc] init]; // 创建UIImageView对象
        [self.contentView addSubview:_imageView01];
        
        _btn = [UIButton buttonWithType:UIButtonTypeCustom];
        [self.contentView addSubview:_btn];
    }
    return self;
}

最后设置一个布局

-(void)layoutSubviews {
    //设置一下自己ui控件的frame
}

这样就可以实现我们的一个自定义cell的内容了。

总结

这里简单介绍了一下有关自定义cell的内容和cell复用的原理。

相关推荐

  1. iOS cell复用以及定义cell

    2024-06-16 17:48:01       39 阅读
  2. cell复用机制和定义cell

    2024-06-16 17:48:01       48 阅读
  3. 97、Cell防止复用两种方法

    2024-06-16 17:48:01       54 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-16 17:48:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-16 17:48:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-16 17:48:01       82 阅读
  4. Python语言-面向对象

    2024-06-16 17:48:01       91 阅读

热门阅读

  1. lwip中server和client的socket、地址和端口号

    2024-06-16 17:48:01       35 阅读
  2. DOM的概念?获取html元素的方法有哪些?

    2024-06-16 17:48:01       25 阅读
  3. 深入浅出Python爬虫:掌握数据抓取的艺术

    2024-06-16 17:48:01       24 阅读
  4. lower_bound 和 upper_bound

    2024-06-16 17:48:01       34 阅读
  5. UOS常用命令

    2024-06-16 17:48:01       23 阅读
  6. Spring Boot 增删改查(mybatis-plus)

    2024-06-16 17:48:01       32 阅读
  7. Vue中双向数据绑定是如何实现的

    2024-06-16 17:48:01       28 阅读
  8. dev c++ “permission denied“解决方法

    2024-06-16 17:48:01       34 阅读
  9. 每天一个项目管理概念之敏捷项目管理

    2024-06-16 17:48:01       31 阅读
  10. MongoDB入门与实践

    2024-06-16 17:48:01       27 阅读
  11. 了解protoStuff

    2024-06-16 17:48:01       33 阅读
  12. 计算机网络期末复习

    2024-06-16 17:48:01       54 阅读
  13. os.system() 函数

    2024-06-16 17:48:01       28 阅读