UITableView中的单元格cell是在显示到用户可视区域后创建的,那么如果用户往下滚动就会继续创建显示在屏幕上的单元格,如果用户向上滚动返回到查看过的内容时同样会重新创建之前已经创建过的单元格。如此一来即使UITableView的内容不是太多,如果用户反复的上下滚动,内存也会瞬间飙升,更何况很多时候UITableView的内容是很多的(例如微博展示列表,基本向下滚动是没有底限的)。
在UITableView中也可以采用类似的方式,只是这时我们不是在滚动到指定位置后更改滚动的位置而是要将当前没有显示的Cell重新显示在将要显示的Cell的位置然后更新其内容。原因就是UITableView中的Cell结构布局可能是不同的,通过重新定位是不可取的,而是需要重用已经不再界面显示的已创建过的Cell。
当然,听起来这么做比较复杂,其实实现起来很简单,因为UITableView已经为我们实现了这种机制。在UITableView内部有一个缓存池,初始化时使用initWithStyle:(UITableViewCellStyle) reuseIdentifier:(NSString *)方法指定一个可重用标识,就可以将这个cell放到缓存池。然后在使用时使用指定的标识去缓存池中取得对应的cell然后修改cell内容即可。
上面的代码中已经打印了cell的地址,如果大家运行测试上下滚动UITableView会发现滚动时创建的cell地址是初始化时已经创建的。
这里再次给大家强调两点:
1. -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)方法调用很频繁,无论是初始化、上下滚动、刷新都会调用此方法,所有在这里执行的操作一定要注意性能;
2. 可重用标识可以有多个,如果在UITableView中有多类结构不同的Cell,可以通过这个标识进行缓存和重新。
exp:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //由于此方法调用十分频繁,cell的标示声明成静态变量有利于性能优化
static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1";
static NSString *cellIdentifierForFirstRow=@"UITableViewCellIdentifierKeyWithSwitch";
//首先根据标示去缓存池取
UITableViewCell *cell;
if (indexPath.row==0) {
cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifierForFirstRow];
}else{
cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
}
//如果缓存池没有取到则重新创建并放到缓存池中
if(!cell){
if (indexPath.row==0) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierForFirstRow];
UISwitch *sw=[[UISwitch alloc]init];
[sw addTarget:self action:@selector(switchValueChange:) forControlEvents:UIControlEventValueChanged];
cell.accessoryView=sw;
}else{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
cell.accessoryType=UITableViewCellAccessoryDetailButton;
}
}
if(indexPath.row==0){
((UISwitch *)cell.accessoryView).tag=indexPath.section;
}
cell.textLabel.text=@"大爷的";
cell.detailTextLabel.text=@"110";
NSLog(@"cell:%@",cell);
return cell;
}