對(duì)于iOS開(kāi)發(fā)者,UITableViewCell的重用是最基本的技能血公,初學(xué)者都應(yīng)該掌握的荷荤。對(duì)于它的原理我就不在此啰嗦了,這里我重點(diǎn)說(shuō)下导绷,如何以正確的姿態(tài)來(lái)重用多類型的UITableViewCell犀勒,正確重用cell不僅僅要重用cell視圖,還需要好好重用cell的子視圖妥曲。你是否做到了呢贾费?
單一類型cell重用
對(duì)于簡(jiǎn)單單一cell的tableView來(lái)講,它的重用我們大多會(huì)在代理方法里這樣寫(xiě):
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//設(shè)置重用標(biāo)識(shí)符
static NSString * Identifier = @"MineCell";
//通過(guò)Identifier取到cell
MineTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier];
//若cell不存在逾一,在進(jìn)行創(chuàng)建
if (!cell) {
cell =[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: Identifier];
}
//用set方法取到對(duì)應(yīng)的model對(duì)cell賦值
[cell cellModel:self.cellModelArr[indexPath.row]];
return cell;
}
或者使用需要注冊(cè)cell的寫(xiě)法:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//設(shè)置重用標(biāo)識(shí)符
static NSString *Identifier = @"MineCell";
MineTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier forIndexPath:indexPath];
//用set方法取到對(duì)應(yīng)的model對(duì)cell賦值
[cell setCellModel:self.cellModelArr[indexPath.row]];
return cell;
}
上面的兩種寫(xiě)法都很簡(jiǎn)單铸本,由于是單一類型的cell重用,不會(huì)涉及到子視圖的重用遵堵,所以沒(méi)什么可講的箱玷。
多類型cell重用
在很多情況下,UITableView并不是單一的一種cell陌宿,而會(huì)包含多種cell锡足,每種cell類型樣式布局都有明顯區(qū)別。這樣來(lái)我們就不能用上面單一的cell重用方式了壳坪。 對(duì)于多類型cell你當(dāng)然可以對(duì)每個(gè)類型的cell創(chuàng)建對(duì)應(yīng)的.h .m文件舶得,并在使用時(shí)引入該 cell的頭文件即可。但可能是出于偷懶爽蝴,我更習(xí)慣統(tǒng)一處理這些cell沐批。把這些cell都寫(xiě)在一個(gè).h .m文件內(nèi),通過(guò)對(duì)不同類型cell設(shè)置對(duì)應(yīng)對(duì)cellStyle枚舉狀態(tài)來(lái)辨別他們蝎亚,這樣以來(lái)九孩,一個(gè)文件就足夠了。
下面就重點(diǎn)說(shuō)下單文件下多類型cell的重用发框。主要代碼如下:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString * MineCellIdentifier = @"MineCellIdentifier";
//通過(guò)注冊(cè)的cell獲取MineTableViewCell
MineTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MineCellIdentifier forIndexPath:indexPath];
//根據(jù)不同row或者也可以根據(jù)model內(nèi)容來(lái)區(qū)分cellStyle
if (indexPath.row == 0) {
//通過(guò)setMineCellStyle:方法對(duì)cell就行類型賦值躺彬,我們會(huì)在 setMineCellStyle:方法里對(duì)cell就行布局等定制化處理。
cell.mineCellStyle = MineTableViewCellStyleOne;
}else
{
cell.mineCellStyle = MineTableViewCellStyleTow;
}
//用set方法取到對(duì)應(yīng)的model對(duì)cell賦值
[cell setCellModel:self.cellModelArr[indexPath.row]];
return cell;
}
我們一般會(huì)在MineTableViewCell.h里定義類似MineTableViewCellStyle的枚舉類型梅惯,并實(shí)現(xiàn)mineCellStyle屬性宪拥,這樣就可以在對(duì)應(yīng)的tableView代理方法里通過(guò)setMineCellStyle:方法來(lái)針對(duì)不同cellStyle布局了。setMineCellStyle:方法內(nèi)部實(shí)現(xiàn)大概如下:
- (void)setMineCellStyle:(MineTableViewCellStyle)mineCellStyle
{
_mineCellStyle = mineCellStyle;
//為了避免cell重用引起的子視圖錯(cuò)亂铣减,我們會(huì)先把cell的子視圖給全不移除她君,下面會(huì)在對(duì)應(yīng)的cellStyle內(nèi)重新創(chuàng)建并添加到cell的contentView內(nèi)。
for (UIView *view in self.contentView.subviews) {
[view removeFromSuperview];
}
//對(duì)不同的類型進(jìn)行針對(duì)性的布局繪制操作
switch (mineCellStyle) {
case MineTableViewCellStyleOne:
{
//這里省略了布局約束的代碼
NSArray *viewArray = @[self.bankNumTitleLb, self.bankNumLb];
for (UIView *view in viewArray) {
[self.contentView addSubview:view];
}
//進(jìn)行布局操作(此處省略不是本文重點(diǎn))
}
break;
case MineTableViewCellStyleTow:
{
//這里省略了布局約束的代碼
NSArray *viewArray = @[self.phoneNumTitleLb, self.phoneNumTextField];
for (UIView *view in viewArray) {
[self.contentView addSubview:view];
}
//進(jìn)行布局操作(此處省略不是本文重點(diǎn))
}
break;
case MineTableViewCellStyleDefault:
{
//這里省略了布局約束的代碼
NSArray *viewArray = @[self.verificationCodeTitleLb,
self.phoneNumTextField,self.verificationCodeButton];
for (UIView *view in viewArray) {
[self.contentView addSubview:view];
}
//進(jìn)行布局操作(此處省略不是本文重點(diǎn))
}
break;
}
}
到這里也許你覺(jué)得一切都沒(méi)什么問(wèn)題葫哗。但有經(jīng)驗(yàn)的開(kāi)發(fā)者可能已經(jīng)看出來(lái)問(wèn)題所在犁河。問(wèn)題出在setMineCellStyle:方法里的這句代碼:
for (UIView *view in self.contentView.subviews) {
[view removeFromSuperview];
}
這句代碼很簡(jiǎn)單鳖枕,就是前面說(shuō)到為了解決cell重用時(shí)會(huì)出現(xiàn)子視圖的重用〗奥荩可是"解決"了子視圖的重用問(wèn)題宾符,那么新問(wèn)題來(lái)了,每次都把子視圖移除灭翔,重新創(chuàng)建既消耗內(nèi)存還占用時(shí)間魏烫,嚴(yán)重會(huì)出現(xiàn)滑動(dòng)出現(xiàn)卡頓現(xiàn)象,而且都刪除了重建還能叫重用嗎肝箱?最多是只是留了個(gè)cell的'殼',里面的'肉'可都是新建的啊哄褒。
因此:在通過(guò)設(shè)置多種cell枚舉類型來(lái)實(shí)現(xiàn)多樣式cell布局時(shí),要先判斷當(dāng)前重用的cellStyle 和 需要設(shè)置的cellStyle是否一致煌张,不一致時(shí)呐赡,才需要重新布局繪制。
修改后的主要代碼如下:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString * MineCellIdentifier = @"MineCellIdentifier";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:MineCellOneIdentifier forIndexPath:indexPath];
//獲取當(dāng)前重用cell的類型cellStyle
MineCellStyle cellStyle = cell.mineCellStyle;
switch (indexPath.section) {
case 0:
{
//如果當(dāng)前重用的cellStyle 和 需要設(shè)置的cellStyle不一致時(shí)骏融,才進(jìn)行類型重制链嘀!
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;
}
這樣以來(lái)即實(shí)現(xiàn)了單文件下實(shí)現(xiàn)多cell類型的功能,又完美的解決了多cell的重用及性能問(wèn)題档玻,如有疏漏不足之處多多指出怀泊。