前面已经说过UITableView中的单元格cell是在显示到用户可视区域后创建的,那么如果用户往下滚动就会继续创建显示在屏幕上的单元格,如果用户向上滚动返回到查看过的内容时同样会重新创建之前已经创建过的单元格。如此一来即使UITableView的内容不是太多,如果用户反复的上下滚动,内存也会瞬间飙升,更何况很多时候UITableView的内容是很多的(例如微博展示列表,基本向下滚动是没有底限的)。
前面一节中我们曾经提到过如何优化UIScrollView,当时就是利用有限的UIImageView动态切换其内容来尽可能减少资源占用。同样的,在UITableView中也可以采用类似的方式,只是这时我们不是在滚动到指定位置后更改滚动的位置而是要将当前没有显示的Cell重新显示在将要显示的Cell的位置然后更新其内容。原因就是UITableView中的Cell结构布局可能是不同的,通过重新定位是不可取的,而是需要重用已经不再界面显示的已创建过的Cell。
当然,听起来这么做比较复杂,其实实现起来很简单,因为UITableView已经为我们实现了这种机制。在UITableView内部有一个缓存池,初始化时使用initWithStyle:(UITableViewCellStyle) reuseIdentifier:(NSString *)方法指定一个可重用标识,就可以将这个cell放到缓存池。然后在使用时使用指定的标识去缓存池中取得对应的cell然后修改cell内容即可。
#pragma mark返回每行的单元格 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //NSIndexPath是一个对象,记录了组和行信息 NSLog(@"生成单元格(组:%i,行%i)",indexPath.section,indexPath.row); KCContactGroup *group=_contacts[indexPath.section]; KCContact *contact=group.contacts[indexPath.row]; //由于此方法调用十分频繁,cell的标示声明成静态变量有利于性能优化 static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1"; //首先根据标识去缓存池取 UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; //如果缓存池没有到则重新创建并放到缓存池中 if(!cell){ cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier]; } cell.textLabel.text=[contact getName]; cell.detailTextLabel.text=contact.phoneNumber; NSLog(@"cell:%@",cell); return cell; }
上面的代码中已经打印了cell的地址,如果大家运行测试上下滚动UITableView会发现滚动时创建的cell地址是初始化时已经创建的。
这里再次给大家强调两点:
-(UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)方法调用很频繁,无论是初始化、上下滚动、刷新都会调用此方法,所有在这里执行的操作一定要注意性能;
可重用标识可以有多个,如果在UITableView中有多类结构不同的Cell,可以通过这个标识进行缓存和重新;
来自:Kenshin Cui's Blog
链接:http://www.cnblogs.com/kenshincui/p/3931948.html#performance