一、cell重用原理
对于UITableView中系统的cell,一般会通过重用cell来达到节省内存的目的:通过为每个cell指定一个重用标识符(reuseIdentifier),即指定了单元格的种类,当cell滚出屏幕时,会将滚出屏幕的单元格放入重用的queue中,当某个未在屏幕上的单元格要显示的时候,就从这个queue中取出单元格进行重用。 即调用dequeueReusableCellWithIdentifier方法来实现。代码如下:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = [NSString stringWithFormat:@"cell"];
UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefaultcellIdentifier] autorelease];
}
return cell;
}
例如:一个table中有20个cell,但是屏幕上最多只能显示10个cell,那么在实际上系统只为其分配了10个cell的内存。当滚动屏幕时,屏幕内显示的cell重复使用这10个cell的内存。
之前有参考过一些资料,解释:在UITableView的头文件中,会找到NSMutableArray *visiableCells,和NSMutableDictionary *reusableTableCells两个结构。visiableCells保存当前显示的cells,reusableTableCells保存可重用的cells。
TableView显示之初,reusableTableCells为空,那么dequeueReusableCellWithIdentifier方法返回nil。开始的10个cell都会走 if(cell == nil) 判断(这里可打断点调试) 通过[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]来创建,并给cell指定同样的重用标识,10个cell全部都加入到visiableCells数组,reusableTableCells为空。
向下拖动tableView,当cell1完全移出屏幕,且cell11完全显示在屏幕上时,cell11加入到visiableCells,cell1移出visiableCells,cell1加入到reusableTableCells。之后的cell都是如此。也许这是比较古老的tableView的头文件,现在搜了一下,貌似找不到这两个容器。
二、cell重用解决办法
对于一些自定义的cell,使用重用机智就会导致出错,因此给出以下两种解决重用机制的方法:
1、通过调用cellForRowAtIndexPath方法根据indexPath准确地取出一行
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"cell";
// UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; //改为以下的方法
UITableViewCell *cell =[tableView cellForRowAtIndexPath:indexPath]; //根据indexPath准确地取出一行,而不是从cell重用队列中取出
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
return cell;
}
2、为每个cell指定不同的重用标识符(reuseIdentifier)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier =[NSString stringWithFormat:@"cell%d%d", [indexPath section], [indexPath row]];//以indexPath来唯一确定cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; //出列可重用的cell
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
return cell;
}