复杂单元格的UITableView速度很慢并且很缓慢

问题描述:

我几乎完成了我的应用程序,似乎所有东西都能正常工作,但主要观点。
这是一个UIViewController与嵌入式UITableView
我使用Parse作为后端,并在我的viewDidLoad方法中获得需要的对象数组。复杂单元格的UITableView速度很慢并且很缓慢

每个单元格都包含一些我在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]; 
} 
+0

你可以发布'CellHT'的代码吗? – jszumski 2013-05-04 15:38:09

+0

我编辑了问题以包含单元代码。 – Aleph72 2013-05-04 15:50:30

+1

你有没有在乐器中进行表格分析? Time Profiler仪器会告诉你准确的时间。 – Fogmeister 2013-05-04 16:00:07

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

  • [UIImage imageWithData:data]
  • 什么关系NSDateFormatter
  • CLLocationinitWithLatitude: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]; 
    } 
}];] 

然后在cellForRowAtIndexPath:,采取预先计算属性,并简单地将它们分配给适当的标签,图像视图等。

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

+0

我已经添加了代码来加载对象的数组 – Aleph72 2013-05-04 15:58:39

+0

@ Aleph72添加了一些代码,让您了解如何将事物移动到'viewDidLoad'。 – jszumski 2013-05-04 16:16:19

+0

我会立即尝试。关于GCD,'findObjectsInBackgroundWithBlock'自动使用后台线程并在需要时调度主线程。 – Aleph72 2013-05-04 16:24:20

试试删除

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]; 

这是一见钟情,然后我看到你所有的代码,我实现了很多图像的使用

+0

删除这些线可以减少很多延迟!但是我需要计算每个对象中包含的点的用户距离,在加载单元格之前我怎么做? – Aleph72 2013-05-04 16:03:14

+0

你必须提前计算它并存储在一个数组中 – 2013-05-04 16:06:31

+0

你的意思是只有一个新的数组? – Aleph72 2013-05-04 16:12:11