tableView:cellForRowAtIndexPath:不仅为可见单元格调用?

时间:2012-02-14 23:57:30

标签: ios uitableview

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

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

因为在我的情况下我的情况很糟糕:我有很多自定义单元格(50~100个单元格),并且每个单元格调用-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)会减慢部分的打开速度,因为每次从nib读取都是已执行并且正在使用图像填充单元格内容。 我检查-(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;
}

它仍然正确吗?或者我错过了什么?

7 个答案:

答案 0 :(得分:5)

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

我在打开部分事件期间使用Instruments指示了内存分配和调用堆栈。它告诉我,大部分时间花在从nib文件加载单元格上。

首先,我所做的是减小nib文件的大小,即最小化自定义tableview单元格中使用的视图数量(现在只有2个视图和2个标签,而不是6个视图,2个图像和2个标签之前)。它给了我一些细胞加载的改善。 Apple文档建议尽可能少地使用视图,不要使用透明度。所以要注意这些建议。

其次,正如我之前发现的那样,并非所有单元格都是由-(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;
}

正如您所看到的,我不是仅仅使用tableview的-(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;
}

因此,我减少了打开具有大量自定义单元格的部分的时间,这可以通过仪器跟踪和体验应用程序时感受到。

答案 1 :(得分:2)

检查你的tableview大小。 可能是你的tableview高度非常大,它一直在加载单元格,直到你的单元格填满所有的tableview大小..

答案 2 :(得分:1)

增加你的

  

估计UITableview的高度。

答案 3 :(得分:1)

只需为UITableViewCell添加估计的高度

问题在我的情况下是:cellforRowAtIndexPath被调用了array.count的次数,而显示的单元格小于array.count。

要解决此问题,我已替换为

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

使用

  • (CGFloat)tableView:(UITableView)tableView EstimatedHeightForRowAtIndexPath:(nonnull NSIndexPath)indexPath;

答案 4 :(得分:0)

这似乎是正确的。优化加载本身的想法在于“dequeueReusableCellWithIdentifier”的工作原理。 如果您正在从远程位置加载图像,那么您可能希望优化代码。但不是来自细胞的加载,因为这看起来是正确的。

答案 5 :(得分:0)

我使用了一些类似的技术,但由于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;
}
顺便说一下;这假设您只使用一个部分。它不适用于多个部分。

答案 6 :(得分:0)

添加其他解决了我的问题。 我重置了对单元格所做的任何更改。

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

}