UICollectionView不重用单元格

时间:2019-07-10 01:15:54

标签: ios objective-c uicollectionview uikit uicollectionviewcell

我正在尝试使用UICollectionView模仿UITableView布局。

layout.itemSize = CGSizeMake(CGRectGetWidth(self.view.bounds), 44.0f);

我注册了可重复使用的单元格类。

[self.collectionView registerClass:[SampleCell class]
            forCellWithReuseIdentifier:NSStringFromClass([SampleCell class])];

注意:SampleClass只是UICollectionViewCell的子类,不包含任何内容。

并符合数据源:

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 28;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([SampleCell class])
                                                                           forIndexPath:indexPath];

    return cell;
}

我发现SampleCell没有被重用。为了验证它,我们可以简单地在UICollectionView中记录子视图的数量。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    NSLog(@"number of subviews in collection view is: %li", (long)self.collectionView.subviews.count);
}

滚动后,我得到了这个日志:

  

集合视图中的子视图数量为:30

     

集合视图中的子视图数量为:30

     

集合视图中的子视图数量为:30

     

集合视图中的子视图数量为:30

请注意,有30个子视图(其中2个是滚动视图指示器)。

这意味着显示的所有28个项目都没有从超级视图中删除不可见的单元格。为什么会这样?

为了简化您的工作,我在Github上提供了一个示例项目。 https://github.com/edwardanthony/UICollectionViewBug

更新:

我还使用内存图层次结构调试器检查了内存分配,并且分配了28次。

2 个答案:

答案 0 :(得分:3)

我确实可以工作,只是由于更积极的缓存而保留了更多的内存。如果您尝试将项目数从28更改为100,则在滚动时会看到它停留在33个子视图中。

尝试将以下代码添加到您的SampleCell类中,您将看到它被调用,但可能与您期望的不太一样。

- (void)prepareForReuse {
    [super prepareForReuse];

    NSLog(@"prepareForReuse called");
}

UICollectionView的缓存方案比UITableView(或至少以前的缓存方案)更高级,这就是您看到自己要做什么的原因。根据文档,它说默认情况下启用单元格预取

  

UICollectionView提供了两种预取技术,可用于   提高响应速度:
  

  • 单元格预取会在   他们需要的时间。当集合视图需要较大的视图时   同时显示的单元数-例如,网格中的新单元格行   布局-要求的单元早于所需的时间   显示。因此,单元格渲染分布在多个布局中   通过,从而获得更流畅的滚动体验。细胞预取   默认情况下启用。

      
  • 数据预取提供了一种机制   系统会在通知您有关收集视图的数据要求   提前要求细胞。如果以下内容有用,   您的单元格依赖昂贵的数据加载过程,例如   网络请求。分配符合以下条件的对象   UICollectionViewDataSourcePrefetching协议   prefetchDataSource属性以接收有关何时进行的通知   预取单元格数据。

  • 您可以通过将以下行添加到示例中的setupCollectionView函数来关闭单元格预取:

    self.collectionView.prefetchingEnabled = NO;
    

    这样做将使您的示例按预期工作。在我的情况下,子视图数将降至18。

    答案 1 :(得分:1)

    我怀疑对子视图进行计数不会反映单元格的重用。子视图可能包含多个对同一单元的引用。要计算使用的单元格数量,您可以记录UICollectionViewCell子类初始化的次数。只需重写它的init方法,然后在其中放置打印语句即可。

    要注意的另一件事(对不起,如果很明显),如果所有单元格都在屏幕上可见,则不会发生重用。当单元在滚动过程中离开屏幕时,就会发生单元重用。