具有复杂单元格的UITableView速度慢且滞后

时间:2013-05-04 15:12:44

标签: ios objective-c uitableview

我差不多完成了我的应用程序,一切似乎都有效,但主要观点 它是UIViewController,嵌入了UITableView 我正在使用Parse作为后端,我在viewDidLoad方法中得到了一个我需要的对象数组。

每个单元格都包含一些我在tableView:cellForRowAtIndexPath中提取的数据,我担心这就是为什么我的表视图如此滞后,但我不知道如何获取数据我需要我的数组中的每个对象而没有indexPath.row数字。

我已经按照其他答案中的建议将每个单元格元素设置为“不透明”。

这是我的代码,非常感谢任何帮助:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"cellHT";
    CellHT *cell = (CellHT *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [[CellHT alloc]
                initWithStyle:UITableViewCellStyleDefault
                reuseIdentifier:CellIdentifier];
    }

    // self.hH is an NSArray containing all the objects
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    cell.lblTitle.text = [self.hH[indexPath.row] objectForKey:@"title"];
    cell.lblVenueName.text = [self.hH[indexPath.row] objectForKey:@"venueName"];
    cell.lblDistance.text = NSLocalizedString(@"Distance from you", nil);
    self.geo = [self.hH[indexPath.row] objectForKey:@"coordinates"];

    // the formatters are initialized in the viewDidLoad: method
    self.formatData = [NSDateFormatter dateFormatFromTemplate:@"dd/MM" options:0 locale:[NSLocale currentLocale]];
    [self.formatterData setDateFormat:self.formatData];
    self.formatOra = [NSDateFormatter dateFormatFromTemplate:@"j:mm" options:0 locale:[NSLocale currentLocale]];
    [self.formatterOra setDateFormat:self.formatOra];
    self.dal = NSLocalizedString(@"from", nil);
    self.ore = NSLocalizedString(@"at", nil);
    CLLocation *vLoc = [[CLLocation alloc] initWithLatitude:self.geo.latitude longitude:self.geo.longitude];
    CLLocation *user = [[CLLocation alloc] initWithLatitude:self.userGeo.latitude longitude:self.userGeo.longitude];
    CLLocationDistance distance = [user distanceFromLocation:venueLoc];
    if ([[prefs objectForKey:@"unit"] isEqualToString:@"km"]) {
        cell.lblDist.text = [NSString stringWithFormat:@"%.1f Km", distance /1000];
    } else {
        cell.lblDist.text = [NSString stringWithFormat:@"%.1f Miles", distance /1609];
    }

    // compare the object's starting date with the current date to set some images in the cell
    NSComparisonResult startCompare = [[self.hH[indexPath.row] objectForKey:@"startDate"] compare: [NSDate date]];
    if (startCompare == NSOrderedDescending) {
        cell.quad.image = [UIImage imageNamed:@"no_HT"];
        cell.lblStartTime.textColor = [UIColor redColor];
    } else {
        cell.quad.image = [UIImage imageNamed:@"yes_HT"];
        cell.lblStartTime.textColor = [UIColor colorWithRed:104.0/255.0 green:166.0/255.0 blue:66.0/255.0 alpha:1.0];
    }
    NSString *dataInizio = [NSString stringWithFormat:@"%@ %@ %@ %@", self.dal, [self.formatterData stringFromDate:[self.hH[indexPath.row] objectForKey:@"startDate"]], self.ore, [self.formatterOra stringFromDate:[self.hH[indexPath.row] objectForKey:@"endDate"]]];
    cell.lblStartTime.text = dataInizio;
    PFObject *cat = [self.hH[indexPath.row] objectForKey:@"catParent"];
    NSString *languageCode = [[NSLocale preferredLanguages] objectAtIndex:0];
    if ([languageCode isEqualToString:@"it"]) {
        cell.lblCategory.text = [cat objectForKey:@"nome_it"];
    } else if ([languageCode isEqualToString:@"es"]) {
        cell.lblCategory.text = [cat objectForKey:@"nome_es"];
    } else {
        cell.lblCategory.text = [cat objectForKey:@"nome_en"];
    }

    //getting the image data from the Parse PFFile
    PFFile *theImage = [self.hH[indexPath.row] objectForKey:@"photo"];
    [theImage getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
        if (!error) {
            cell.cellImageView.image = [UIImage imageWithData:data];
        }
    }];

    //getting the cell object's owner and his profile
    PFUser *usr = [self.hH[indexPath.row] objectForKey:@"parent"];
    PFQuery *prof = [PFQuery queryWithClassName:@"Profile"];
    prof.cachePolicy = kPFCachePolicyCacheThenNetwork;
    [prof whereKey:@"parent" equalTo:usr];
    [prof getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
        if (!error) {
            //getting the object's rating and the number of votes
            PFQuery *rateQuery = [PFQuery queryWithClassName:@"Rating"];
            [rateQuery whereKey:@"parent" equalTo:object];
            [rateQuery getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
                if (!error) {
                    float vote = [[object objectForKey:@"rate"] floatValue];
                    float temp = ((vote * 2) + 0.5);
                    int tempvote = (int)temp;
                    float roundedVote = (float)tempvote / 2;
                    // drawing the stars number, depending on the rating obtained
                    UIImage *starsImage = [UIImage imageNamed:@"stars"];
                    UIGraphicsBeginImageContextWithOptions(cell.imgVoto.frame.size, NO, 0);
                    CGPoint starPoint = (CGPoint) {
                        .y = (cell.imgVoto.frame.size.height * (2 * roundedVote + 1)) - (starsImage.size.height)
                    };
                    [starsImage drawAtPoint:starPoint];
                    cell.imgVoto.image = UIGraphicsGetImageFromCurrentImageContext();
                    UIGraphicsEndImageContext();
                    cell.lblVoto.text = [NSString stringWithFormat:@"(%d)", [[object objectForKey:@"voters"] intValue]];
                }
            }];
        }
       }];
    return cell;
}

编辑:这是单元格代码:

+ (void)initialize {
    if (self != [HH class]) {
        return;
    }
}

-(id)initWithCoder:(NSCoder *)aDecoder {
    if ( !(self = [super initWithCoder:aDecoder]) ) return nil;

    self.cellImageView.image = [UIImage imageNamed:@"icona_foto"];
    self.cellImageView.contentMode = UIViewContentModeScaleToFill;
    self.formatterData = [[NSDateFormatter alloc] init];
    self.formatData = [[NSString alloc] init];
    self.formatterOra = [[NSDateFormatter alloc] init];
    self.formatOra = [[NSString alloc] init];
    self.formatData = [NSDateFormatter dateFormatFromTemplate:@"dd/MM" options:0 locale:[NSLocale currentLocale]];
    [self.formatterData setDateFormat:self.formatData];
    self.formatOra = [NSDateFormatter dateFormatFromTemplate:@"j:mm" options:0 locale:[NSLocale currentLocale]];
    [self.formatterOra setDateFormat:self.formatOra];
    self.lblVoto.text = @"(0)";

    return self;
}

第二次编辑:这是viewDidLoad方法中的代码:

        PFQuery *hours = [PFQuery queryWithClassName:@"HH"];
        hours.cachePolicy = kPFCachePolicyCacheThenNetwork;
        // here I'm making lots of query constraints that I'll not include

        [hours findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
            if (!error) {
                self.objectsNumber = objects.count;
                self.hH = [[NSArray alloc] initWithArray:objects];
            }
        }];
        [self.tableView reloadData];
}

3 个答案:

答案 0 :(得分:4)

我会尽可能多地移动cellForRowAtIndexPath:的逻辑,它需要非常轻量级才能获得良好的滚动性能。你在主线程上做了很多工作,当你从Parse返回你的模型对象时我会做更多的工作(如果你可以发布viewDidLoad我可以给你更具体的帮助)完成这些调用后更新表视图:

  • [UIImage imageWithData:data]
  • NSDateFormatter
  • 有关
  • CLLocation的{​​{1}}
  • 创建评级星星图片

这些都不依赖于表视图的状态,因此可以在模型对象中有效地预先计算和缓存它们。如果你只是简单地在桌子上滚动,你就会一遍又一遍地做同样的工作,从而导致你的表现无效。


更新了提问者的最新代码:

我不会在此处包含您的所有功能,但这应该会给您一个想法:

initWithLatitude:longitude:

然后在// create a single shared formatter instead of one per object NSDateFormatter *dateFormatter = [NSDateFormatter dateFormatFromTemplate:@"dd/MM" options:0 locale:[NSLocale currentLocale]]; NSDateFormatter *timeFormatter = [NSDateFormatter dateFormatFromTemplate:@"j:mm" options:0 locale:[NSLocale currentLocale]]; [hours findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) { if (!error) { self.objectsNumber = objects.count; for (SomeObject *modelObj in objects) { // if you can add properties to your model object directly, do that // otherwise write a category on the Parse object to add the ones you need modelObj.dateString = [NSString stringWithFormat:@"%@ %@ %@ %@", modelObj.dal, [self.dateFormatter stringFromDate:[modelObj objectForKey:@"startDate"]], modelObj.ore, [self.timeFormatter stringFromDate:[modelObj objectForKey:@"endDate"]]]; // create your locations, images, etc in here too } self.hH = [[NSArray alloc] initWithArray:objects]; } }];] 中,获取预先计算的属性,只需将它们分配给相应的标签,图片视图等。

通过GCD从主线程中完成大部分处理会更好,但这很可能超出了这个问题的范围。有关详细信息,请参阅Using GCD and Blocks Effectively。请记住,只从主线程中与UIKit进行交互!

答案 1 :(得分:1)

尝试删除

CLLocation *vLoc = [[CLLocation alloc] initWithLatitude:self.geo.latitude longitude:self.geo.longitude];

CLLocation *user = [[CLLocation alloc] initWithLatitude:self.userGeo.latitude long  itude:self.userGeo.longitude];

CLLocationDistance distance = [user distanceFromLocation:venueLoc];

这是乍一看,然后我看到你所有的代码,我意识到使用了很多图像

答案 2 :(得分:0)

因为UITableView需要一些时间来布置单元格。

解决方案:

步骤1。将节号和行号设置为0

步骤2。在viewDidAppear中重新加载tableView。

然后您的视图控制器云响应迅速,然后显示单元格。