UITableView滚动时出现延迟。

4

我正在尝试实现类似iOS 6日历中的事件表。

我有一个带有500个行(事件)的UITableView。当我开始滚动时,动画是流畅的。

但在两百行之后开始出现卡顿。在本机iOS 6日历事件列表中,所有工作都很顺畅。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    double begin = CFAbsoluteTimeGetCurrent();
    if(!self.isNoResults)
    {
        NSString *cellIdentifier = [NSString stringWithFormat: @"Cell %i %i", indexPath.row, indexPath.section];
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
        UIImageView *circleImgView;
        NSString *startTimeStr;
        NSDateFormatter *formatter;
        UILabel *timeLbl;
        UILabel *titleLbl;
        UILabel *endsLbl;
        UIImageView *eventTypeImgView;
        if(cell == nil)
        {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
            circleImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"newMesIcon.png"]];
            circleImgView.frame = CGRectMake(14, 19, 12, 12);
            [cell.contentView addSubview:circleImgView];



            timeLbl = [[UILabel alloc] init];
            [timeLbl setBackgroundColor:[UIColor clearColor]];
            timeLbl.frame = CGRectMake(35, 15, 200, 20);
            timeLbl.font = [UIFont systemFontOfSize:13];
            timeLbl.tag = 333;
            [cell.contentView addSubview:timeLbl];

            titleLbl = [[UILabel alloc] init];
            titleLbl.frame = CGRectMake(123, 15, 200, 20);
            titleLbl.font = [UIFont fontWithName:@"Arial-BoldMT" size:18];
            [titleLbl setBackgroundColor:[UIColor clearColor]];
            titleLbl.tag = 444;
            [cell.contentView addSubview:titleLbl];
            [cell.contentView setBackgroundColor:[UIColor colorWithRed:243 / 255.0 green:245 / 255.0 blue:247 / 255.0 alpha:1.0]];

            endsLbl = [[UILabel alloc] init];
            [endsLbl setBackgroundColor:[UIColor clearColor]];
            endsLbl.frame = CGRectMake(49, 11, 40, 8);
            [endsLbl setFont:[UIFont fontWithName:@"Arial-BoldMT" size:7]];
            [endsLbl setTextColor:[UIColor redColor]];
            endsLbl.tag = 555;
            [cell.contentView addSubview:endsLbl];

            eventTypeImgView = [[UIImageView alloc] init];
            eventTypeImgView.frame = CGRectMake(95, 16, 16, 17);
            eventTypeImgView.tag = 666;
            [cell.contentView addSubview:eventTypeImgView];
        }


        startTimeStr = [[self.sortedEventsDict[[[[self.sortedEventsDict allKeys] sortedArrayUsingSelector:@selector(compare:)] objectAtIndex:indexPath.section]]  objectAtIndex:indexPath.row] valueForKey:@"starts"];

        formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"yyy-MM-dd HH:mm"];
        NSDate *startDate = [formatter dateFromString:startTimeStr];
        NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
        [timeFormatter setDateFormat:@"HH:mm"];
        NSString *timeStr = [timeFormatter stringFromDate:startDate];


        NSString *endTimeStr = [[self.sortedEventsDict[[[[self.sortedEventsDict allKeys] sortedArrayUsingSelector:@selector(compare:)] objectAtIndex:indexPath.section]]  objectAtIndex:indexPath.row] valueForKey:@"ends"];
        NSDateFormatter *endformatter = [[NSDateFormatter alloc] init];
        [endformatter setDateFormat:@"yyy-MM-dd HH:mm"];
        NSDate *endDate = [endformatter dateFromString:endTimeStr];
        NSDateFormatter *endtimeFormatter = [[NSDateFormatter alloc] init];
        [endtimeFormatter setDateFormat:@"HH:mm"];
        NSString *endTime = [endtimeFormatter stringFromDate:endDate];


        if([[[self.sortedEventsDict[[[[self.sortedEventsDict allKeys] sortedArrayUsingSelector:@selector(compare:)] objectAtIndex:indexPath.section]]  objectAtIndex:indexPath.row] valueForKey:@"type"] isEqualToString:@"event"])
        {
            ((UIImageView *)[cell.contentView viewWithTag:666]).image = [UIImage imageNamed:@"eventsIcon.png"];
        }
        else
        {
            ((UIImageView *)[cell.contentView viewWithTag:666]).image = [UIImage imageNamed:@"appointmentsIcon.png"];
        }

        ((UILabel *)[cell.contentView viewWithTag:555]).text = @"";
        if([timeStr isEqualToString:@"00:00"] && [endTime isEqualToString:@"23:59"])
        {
            timeStr = @"all-day";

        }

        else if([timeStr isEqualToString:@"00:00"] && ![endTime isEqualToString:@"23:59"])
        {
            timeStr = endTime;

            ((UILabel *)[cell.contentView viewWithTag:555]).text = @"ENDS";

        }


        ((UILabel *)[cell.contentView viewWithTag:333]).text = timeStr;
        ((UILabel *)[cell.contentView viewWithTag:444]).text = [[self.sortedEventsDict[[[[self.sortedEventsDict allKeys] sortedArrayUsingSelector:@selector(compare:)] objectAtIndex:indexPath.section]]  objectAtIndex:indexPath.row] valueForKey:@"title"];

        startDate = nil;
        timeFormatter = nil;
        timeStr = nil;
        endTimeStr = nil;
        endformatter = nil;
        endDate = nil;
        endtimeFormatter = nil;
        endTime = nil;
        startTimeStr = nil;
        formatter = nil;
        [cell setBackgroundColor:[UIColor colorWithRed:243 / 255.0 green:245 / 255.0 blue:247 / 255.0 alpha:1.0]];
        double finish = CFAbsoluteTimeGetCurrent();
        NSLog(@"TIME DIFF = %f", finish - begin);
        return cell;
    }
    else
    {
        NSString *cellIdentifier = [NSString stringWithFormat: @"Cell No Results %i %i", indexPath.row, indexPath.section];
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
        if(cell == nil)
        {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
            if(indexPath.row == 2)
            {
                UILabel *noResultsLbl = [[UILabel alloc] init];
                noResultsLbl.text = self.noResultsString;
                [noResultsLbl setFont:[UIFont fontWithName:@"Arial-BoldMT" size:20]];
                [noResultsLbl setTextColor:[UIColor colorWithRed:204 / 255.0 green:204 / 255.0 blue:204 / 255.0 alpha:1.0]];
                noResultsLbl.frame = CGRectMake(60, 15, 200, 20);
                noResultsLbl.textAlignment = NSTextAlignmentCenter;
                [cell.contentView addSubview:noResultsLbl];
            }

        }
        [cell.contentView setBackgroundColor:[UIColor colorWithRed:243 / 255.0 green:245 / 255.0 blue:247 / 255.0 alpha:1.0]];
        cell.userInteractionEnabled = NO;
        double finish = CFAbsoluteTimeGetCurrent();
        NSLog(@"TIME DIFF = %f", finish - begin);
        return cell;
    }
}

请帮助我。


1
你为表格视图中的每个单元格创建了两个日期格式化程序。这肯定会使你的应用程序崩溃。 - Zack Brown
2
使用工具来测量实际问题所在,其他一切都只是猜测。 - David Rönnqvist
感谢大家的帮助。我给大家点个赞。 - Kisel Alexander
使用Instruments,就像@David Rönnqvist建议的那样。在我的情况下,我对Attributedtext进行了一些NSUTF8StringEncoding操作。Instruments指出这是一个繁重的操作。我重写了它,我的性能恢复到了60 fps。 - Sjakelien
6个回答

7
您的 cellForRowAtIndexPath 函数有140行代码,这就是导致其运行不流畅的原因。我建议您复查一下代码,并尝试尽可能地进行重构。格式化器的开销非常大,而您正在分配和初始化多个格式化器。建议使用基于原型或xib的单元格,而不是每次以编程方式设置它。我还建议不要使用标签来表示视图,请将其放入一个xib或原型单元格中,并将其设置为outlet。

这些更改将加快您的滚动速度。


3

检查您在单元格中使用的图像大小。 我曾经遇到过这个问题,当时图片比它们实际需要的尺寸要大。尝试将图像大小减小到表格的最佳大小。


我有一个带有图片的表格视图,并且我通过调整图片大小解决了表格的卡顿问题。谢谢!重要提示 调整图片大小的正确方法:http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/ - Thomás Pereira

2
你需要为每个单元格中的所有数据进行排序。
if([[[self.sortedEventsDict[[[[self.sortedEventsDict allKeys] sortedArrayUsingSelector:@selector(compare:)] objectAtIndex:indexPath.section]]  objectAtIndex:indexPath.row] valueForKey:@"type"] isEqualToString:@"event"])

尝试在每次[table reloadData]调用时使用准备好的数据。基本上,您可以在一个地方执行所有计算,然后只需使用结果填充单元格。

找出问题所在的最佳方法是使用Profiler。它将向您显示哪个代码部分在帧之间占用了所有CPU。


1

没有单元格重用,多次分配和初始化以及很多使用NSDateFormatter的操作,这非常昂贵。

待办事项:

  1. 子类化UITableViewCell并创建自定义单元格
  2. 使用常量标识符重用单元格
  3. 使用DFDateFormatterFactory重用NSDateFormatter或手动使用按格式分开的NSDateFormatter,因为每个格式就像一个新的格式化程序

重用单元格:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath      *)indexPath
{
     static NSString *CellIdentifier = @"cell";
     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (!cell) {
// Setup new cell and constant elements of cell
    }

// Setup data like images, strings and stuff with minimal calculations and formatting
     return cell;
}

1
我的解决方案可能只适用于很少见的情况,但肯定有帮助。
我有一个单元格,其中包含一个带有货币符号"₽"(我认为这也可能是其他货币字符引起的)的标签字符串。每次重用单元格时都会动态添加此字符串到标签中,因此表格视图非常卡顿。然后我仅删除了卢布符号,卡顿问题消失了。
解决方案:创建一个准备好的标签,并从故事板中将字符输入到标签中。

0

对我来说,卡顿是由主tableView单元格内的另一个tableView引起的(很奇怪的情况,我知道)。我通过删除额外的tableView并重新思考我的应用程序架构,避免了“tableView内嵌tableView”的方法来解决这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接