iOS基礎控件--UITableView之自定義cell和cell的複用

在上一篇文章中有下面一段代碼:

cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];

這裏創建cell的時候設置了一個系統style和一個identifier
這裏的兩個屬性就是今天這篇文章的內容:自定義cell和cell複用。

自定義cell

在通常的開發中,系統默認的cell樣式並不能滿足設計需求,所以自定義cell樣式就是很基本的操作。
下面來簡單實現一個和微信通訊錄類似的cell:下面是全部代碼
CustomerCell.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface CustomerCell : UITableViewCell
//聲明兩個屬性,用於給視圖賦值
@property (nonatomic, copy)NSString *title;
@property (nonatomic, copy)UIImage *image;

@end

NS_ASSUME_NONNULL_END

CustomerCell.m

#import "CustomerCell.h"

@implementation CustomerCell
{
    //聲明兩個視圖
    UILabel *titleLabel;
    UIImageView *iconView;
}

//重寫init方法
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    //調用父類init方法創建
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        //創建成功則t給cell添加需要的子視圖
        titleLabel = [[UILabel alloc] init];
        [self.contentView addSubview:titleLabel];
        
        iconView = [[UIImageView alloc] init];
        [self.contentView addSubview:iconView];
    }
    
    return self;
}

//重寫layoutSubviews方法,給視圖設置位置大小
- (void)layoutSubviews{
    iconView.frame = CGRectMake(20, 5, 54, 54);
    iconView.layer.masksToBounds = YES;
    iconView.layer.cornerRadius = 4;
    titleLabel.frame = CGRectMake(80, 5, 100, 30);
}

- (void)setTitle:(NSString *)title{
    titleLabel.text = title;
}

- (void)setImage:(UIImage *)image{
    iconView.image = image;
}

- (void)awakeFromNib {
    [super awakeFromNib];
    // Initialization code
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

@end

ViewController.m中調用

#import "ViewController.h"
#import "CustomerCell.h"

@interface ViewController ()<UITableViewDelegate, UITableViewDataSource>//添加協議
{
    //聲明tableView和數據源
    UITableView *table;
    NSMutableArray *titleArray;
    NSMutableArray *imageArray;
}
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self createDataSource];
    [self createTableView];
}

//創建數據源
- (void)createDataSource{
    //初始化數據源數組
    titleArray = [NSMutableArray arrayWithCapacity:0];
    imageArray = [NSMutableArray arrayWithCapacity:0];
    //循環給數據源中添加元素
    for (int i = 0; i < 14; i++) {
        NSString *string = [NSString stringWithFormat:@"第%d行", i+1];
        [titleArray addObject:string];
        
        NSString *imageName = [NSString stringWithFormat:@"image_%.2d.jpg", i+1];
        UIImage *image = [UIImage imageNamed:imageName];
        [imageArray addObject:image];
    }
    //刷新視圖
    [table reloadData];
}

//創建tableView視圖
- (void)createTableView{
    //創建並設置位置大小和風格形式
    table = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
    //設置代理
    table.delegate = self;
    table.dataSource = self;
    //設置縱橫滑塊不顯示
    table.showsVerticalScrollIndicator = NO;
    table.showsHorizontalScrollIndicator = NO;
    [self.view addSubview:table];
}

#define mark --UITableViewDelegate
//設置列表中每個元素的行高,在非動態行高的情況下設置固定值。動態行高的情況需要計算。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 64;
}

//設置列表中元素的個數  一般設置爲數據源中元素的個數
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return titleArray.count;
}

//創建tableView中的每一個cell,這裏使用複用機制。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    CustomerCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (cell == nil) {
        cell = [[CustomerCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
    }
    cell.title = titleArray[indexPath.row];
    cell.image = imageArray[indexPath.row];
    
    return cell;
}

@end

cell複用

//創建tableView中的每一個cell,這裏使用複用機制。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    CustomerCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (cell == nil) {
        cell = [[CustomerCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
    }
    cell.title = titleArray[indexPath.row];
    cell.image = imageArray[indexPath.row];
    
    return cell;
}

在上面的代碼的解釋是:調用代理方法創建並使用cell,在每次使用cell的時候先從複用池中去找Identifier爲“cell”的cell,找到以後就使用,沒有就創建一個新的。如下圖:
複用池理解

cell的複用機制是複用池的使用,複用池的意思是創建的cell都在池中,每一個cell都有一個Identifier作爲標記,在從複用池中取cell的時候會根據Identifier取出,當沒有找到的時候纔去創建,這樣的方式會儘可能少的創建cell以達到優化內存的效果。
複用池的實現是一個字典數組,大致可以理解爲:array = [@{@“cell”:cell1, @“Identifier”: @“cell”},@{@“cell”:cell2, @“Identifier”: @“cell”}…];

cell的複用雖然節約了內存,但是有時也會帶來一些麻煩,比如在一個帶有UITextField的cell上,當cell滾動時,前面輸入到textView上的文字會因爲複用的問題而消失。這是一個比較嚴重的問題。在下一篇文章中再去研究帶有UITextField的cell如何避免cell複用而帶來的問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章