tableView:cellForRowAtIndexPath:get不仅对可见单元格调用



我有一个带有部分的tableView,它可以打开和关闭。因此,当我点击一个部分打开它时,它会被单元格填满,-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)被调用的次数与我在-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section中提供的次数完全相同。

这是正确的吗?不应该只是可见细胞的数量吗?

因为在我的情况下,我的情况很糟糕:我有很多自定义单元格(50~100个单元格),为每个单元格调用-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)会减慢部分的打开速度,因为每次从笔尖读取时,单元格内容都会填充图像。我检查了-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)内细胞的可见性,如下所示:

if ([[self.tableView indexPathsForVisibleRows] containsObject:indexPath])
    NSLog(@"visible %@", indexPath);

结果显示,在45个细胞中,只有6或7个可见。其他人在可见区域之外。但创建细胞仍然有效。这是代码:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath    {
static NSString *CellIdentifier = @"IVCell";
IVCamera *camera = [server.cameras objectAtIndex:indexPath.row];
IVServerListViewCell *cell = (IVServerListViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    [[NSBundle mainBundle] loadNibNamed:@"IVServerListCell" owner:self options:nil];
    cell = (IVServerListViewCell*)_tableViewCell;
    self.tableViewCell = nil;
}
[cell textLabel].text = camera.cameraName;
cell.preview = camera.preview;
cell.userData = camera; 
cell.isEnabled = (server.isInactive)?NO:camera.isOnline;
return cell;
}

它仍然正确吗?还是我错过了什么?

增加

UITableview的估计LowHeight。

好吧,我以某种方式解决了我的问题。以下是我如何得出解决方案的想法和想法。也许这对某人有帮助。

我已经指导了内存分配和调用堆栈使用仪器在打开部分的事件。它告诉我,大部分时间都花在从笔尖文件加载单元格上。

首先,我所做的是缩小nib文件的大小,即最大限度地减少自定义表视图单元格中使用的视图数量(现在只有2个视图和2个标签,而不是以前的6个视图、2个图像和2个标记)。它让我在细胞负载方面有所提高。苹果公司的文档建议尽可能少地使用视图,不要使用透明度。所以要注意这些建议。

其次,正如我之前发现的,并不是所有由-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)创建的单元格都是可见的,我决定以某种方式减少从nib文件加载新单元格的数量。为了实现这一点,我想出了一个简单的想法:为不可见的行返回空白的默认单元格,而为可见的行从nib加载自定义单元格。这是一段代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([self index:indexPath isInvisibleInTableView:tableView])
        return [self getBlankCellForTableView:tableView];
    // the rest of the method is the same
    ...
}
-(BOOL)index:(NSIndexPath*)indexPath isInvisibleInTableView:(UITableView*)tableView
{
    NSMutableArray *visibleIndexPaths = [self getExtendedVisibleIndexPathsForTableView:tableView];
    return ![visibleIndexPaths containsObject:indexPath];
}
-(UITableViewCell*)getBlankCellForTableView:(UITableView*)tableView
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"IVBlankCell"];
    if (!cell)
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"IVBlankCell"] autorelease];
    return cell;
}

正如您所看到的,我不仅仅使用表视图的-(NSArray*)indexPathsForVisibleRows方法来检测可见单元格。相反,我编写了自己的方法-(NSMutableArray*)getExtendedVisibleIndexPathsForTableView:(UITableView*)tableView。这是必要的,因为出于某种原因,当使用-(NSArray*)indexPathsForVisibleRows时,最后一个可见单元格旁边的单元格或第一个可见单元格前面的单元格被创建为空白单元格,并且在滚动时看起来像空单元格。为了克服这一点,在-(NSMutableArray*)getExtendedVisibleIndexPathsForTableView: (UITableView*)tableView中,我将边界单元添加到可见阵列单元中:

-(NSMutableArray*)getExtendedVisibleIndexPathsForTableView:(UITableView*)tableView{
    NSArray *visibleIPs = [tableView indexPathsForVisibleRows];
    if (!visibleIPs || ![visibleIPs count])
        return [NSMutableArray array];
    NSIndexPath *firstVisibleIP = [visibleIPs objectAtIndex:0];
    NSIndexPath *lastVisibleIP = [visibleIPs objectAtIndex:[visibleIPs count]-1];
    NSIndexPath *prevIndex = ([firstVisibleIP row])?[NSIndexPath indexPathForRow:[firstVisibleIP row]-1  inSection:[firstVisibleIP section]]:nil;
    NSIndexPath *nextIndex = [NSIndexPath indexPathForRow:[lastVisibleIP row]+1 inSection:[lastVisibleIP section]];
    NSMutableArray *exVisibleIndexPaths = [NSMutableArray arrayWithArray:[tableView indexPathsForVisibleRows]];
    if (prevIndex)
        [exVisibleIndexPaths addObject:prevIndex];
    [exVisibleIndexPaths addObject:nextIndex];
    return exVisibleIndexPaths;
}

因此,我减少了打开带有大量自定义单元格的部分的时间,这一点得到了Instruments追踪的证明,并在体验应用程序时感受到了这一点。

只需添加UITableViewCell 的估计高度

在我的案例中,问题是:cellforRowAtIndexPath被调用array.count的次数,而显示的单元格小于array.count。

为了解决这个问题,我刚刚更换了

  • (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath

带有,

  • (CGFloat)tableView:(UITableView)tableView估计高度ForRowAtIndexPath:(nonnull NSIndexPath)indexPath

检查您的表视图大小。可能是因为您的表视图高度非常大,所以它会一直加载单元格,直到您的单元格填满所有表视图大小。。

这似乎是正确的。优化加载本身的思想在于"dequeueReusableCellWithIdentifier"的工作方式。如果你从一个远程位置加载图像,这就是你想要优化代码的地方。但不是来自细胞的负载,因为这在这里看起来是正确的。

我使用了一些类似的技术,但由于indexPathsForVisibleRows是排序的,所以不需要使用containsObject。相反,你可以做:

//
// Checks if indexPath is visible in current scroll state, we are expanding bounds by 1
// because the cells that are next to the last one visible or the cells that are previous
// to the first one visible could look empty while scrolling.
//
- (BOOL)isIndexPathVisible:(NSIndexPath *)indexPath
{
    NSInteger row = [indexPath row];
    NSArray *visible = [self.tableView indexPathsForVisibleRows];
    NSInteger count = [visible count];
    NSInteger first = (count > 0) ? MAX([visible[0] row] - 1, 0): 0;
    NSInteger last = (count > 1) ? [visible[1] row] + 1: first + 2;
    return row >= first && row <= last;
}

顺便说一下;这假设您只使用一个部分。它不适用于多个部分。

添加else解决了我的问题。我在哪里重新设定了对单元格所做的任何更改。

if (! self.cell) {
    self.cell = [[LanguageCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    self.cell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
    self.cell.checkImage.image = NO;
}

最新更新