tableView重用机制

一 重用机制简介

首先我们需要搞明白为什么要使用重用机制,它的原理是什么.

无论是UITableView还是UICollectionView,都有许多需要显示的cell (item), 但是屏幕的大小是有限的,一次只能显示那么几个,如果我们把所有的数据全部都加载进去,暂时又看不到,就会非常浪费内存.

那么该如何避免这种不必要的内存消耗呢?就是每次只显示屏幕能放得下的cell的数据,在用户滑动屏幕的过程中,再去加载新的数据,于是就有了cell的重用机制

重用机制实现了数据和显示的分离,并不会为每个要显示的数据都创建一个Cell,一般情况下只创建屏幕可显示的最大的cell个数+1,每当有一个cell从屏幕消失,就将其放到缓存池中,如果有新的cell出现,就去缓存池中取,如果缓存池中没有,再创建。

---->这种机制下系统默认有一个可变数组 NSMutableArray* visiableCells, 用来保存当前显示的cell. 还有一个可变字典 NSMutableDictnery* reusableTableCells, 用来保存可重复利用的cell. 之所以用字典是因为可重用的cell有不止一种样式,我们需要根据它的reuseIdentifier(重用标识符)来查找是否有可重用的该样式的cell.

二 重用机制简介如何解决一些重用cell

1.cell创建使用[tableView 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]; 
    } 
     //...其他代码                               
} 

将获得cell的方法从- (UITableViewCell)dequeueReusableCellWithIdentifier:(NSString)identifier 换为-(UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;重用机制调用的就是dequeueReusableCellWithIdentifier这个方法,方法的意思就是“出列可重用的cell”,因而只要将它换为cellForRowAtIndexPath(只从要更新的cell的那一行取出cell),就可以不使用重用机制,因而问题就可以得到解决,但是会浪费一些空间。(不建议使用)

2.不同标识符

- (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]; 
    } 
    //...其他代码 
} 

通过为每个cell指定不同的重用标识符(reuseIdentifier)来解决。重用机制是根据相同的标识符来重用cell的,标识符不同的cell不能彼此重用。于是我们将每个cell的标识符都设置为不同,就可以避免不同cell重用的问题了。

3.删除重用cell的所有子视图

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //出列可重用的cell 
    if (cell == nil) { 
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 
    } 
    else 
    { 
        //删除cell的所有子视图 
        while ([cell.contentView.subviews lastObject] != nil) 
        { 
            [(UIView*)[cell.contentView.subviews lastObject] removeFromSuperview]; 
        } 
    } 
    //...其他代码 
}

这个方法是通过删除重用的cell的所有子视图,从而得到一个没有特殊格式的cell,供其他cell重用。考虑到内存问题,cell少得时候可以每个都添加标识符,当cell重用较多时,考虑内存问题,建议用删除cell的所有子视图方法(做视频播放的时候).

4.cell做一个tag标记,对cell将要展示的差异内容进行判断

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
     cell.myLabel.text = [NSString stringWithFormat:@"我的Label%ld", indexPath.row];
      cell.tag = indexPath.row;
      if (cell.tag == 5) {
          cell.imageVIew.backgroundColor = [UIColor greenColor];
      }
      if (cell.tag != 5) {
          cell.imageVIew.backgroundColor = [UIColor whiteColor];
     }
     return cell;
 }

三 区分一下重用cell的两个方法

//方法一
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

//方法二
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

在iOS文档中对方法二有这样的特殊描述:important


文档截图

不同之处:
1.方法二中总是返回一个有效的UITableViewCell
2.方法二的正确使用方法。这里解释说要先进行注册我们自定义或者通过nib的类和标识符,然后再使用方法二进行重用。所以现在我们崩溃的原因就已经明确了,问题就出在没有进行先注册我们自定义的类和标识符。(先注册,就不需要判空操作)

所以....以后使用可以如下

方法一:判空操作
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    MeetingReplyBasicCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BasicCell"];
    if (!cell) {
        cell = [[MeetingReplyBasicCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"BasicCell"];
    }
    
    return cell;
}

方法二:注册操作
[self.tableView registerClass:[MeetingReplyBasicCell class] forCellReuseIdentifier:@"BasicCell"];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    MeetingReplyBasicCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BasicCell" forIndexPath:indexPath];
    
    return cell;
}

你可能感兴趣的:(tableView重用机制)