最近編寫新功能的時候,偶然間發現有較少開發經驗的開發人員對于表視圖的單元格的複用問題并不是了解的很透徹,是以在此通過代碼的形式快速的教給大家如何了解和運用單元格的複用問題。表視圖是在開發中經常使用的控件,而且有時處理的内容量也是非常巨大的,這就需要考慮表視圖的性能優化,而最基本的性能優化則是單元格的複用,正所謂基礎打得好,才能飛得高,是以需要很好的了解單元格是如何複用的。
在表視圖顯示的時候,會建立 (視圖中可看的單元格個數+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
通過列印的位址我們可以看出複用:
兩種單元格的複用的方式存在着細微的差别,新手一般情況下會不太了解,但是隻要仔細觀看以上的代碼,或者将代碼直接粘貼到新建立的工程中去,然後運作,可以得出和我截圖出的一樣的結果。希望以上代碼能夠幫助對于表視圖的單元格複用不太了解的開發人群。當然這裡隻是簡單的講解了一下單元格的重用機制,在實際的開發過程中,可能會因為不同的展示效果,需要合理的利用單元格的複用。