2

你好:我在我的应用程序中使用了一个集合视图,我注意到使用reloadData刷新需要比预期更长的时间。我的收藏视图有1 section,我正在用5 cell s(每个有2个按钮和一个标签)测试它。我在代码中放入了一些日志,以显示系统实际上需要刷新多长时间。有趣的是,日志表明它比现在刷新得更快。在设备上,例如,它会占用到约0.2秒(明显),但这里有日志:UICollectionView reloadData看起来很慢/迟缓(不是瞬时的)

0.007s从时间reloadData被调用时cellForItemAtIndexPath被称为第一次

0.002s每个单元加载并返回

0.041s从时间reloadData调用到小区#5返回

有没有什么在cellForItemAtIndexPath功能(巴斯特别强烈的时候cally只能在NSArrayindexPathrow处找到一个有3个值的字典。 即使当我删除这个,只是返回一个空白按钮的单元格,但我看到了相同的行为。

有没有人有任何想法,为什么这可能会发生?顺便说一下,它只发生在物理设备(iPad Air)上。谢谢!

编辑#1

每@布莱恩 - 镍的评论,我所使用的时间轮廓仪,并发现它不是每次reloadData被称为确实秒杀。下面是截图:

Time Profiler

@ArtSabintsev,这里是周边reloadData通话功能,其次是cellForItemAtIndexPath

//Arrays were just reset, load new data into them 
//Loop through each team 
for (NSString *team in moveUnitsView.teamsDisplaying) { //CURRENT TEAM WILL COME FIRST 

    //Create an array for this team 
    NSMutableArray *teamArr = [NSMutableArray new]; 

    //Loop through all units 
    for (int i = [Universal units]; i > 0; i--) { 

     //Set the unit type to a string 
     NSString *unitType = [Universal unitWithTag:i]; 

     //Get counts depending on the team 
     if ([team isEqualToString:currentTeam.text]) { 

      //Get the number of units of this type so that it supports units on transports. If the territory is a sea territory and the current unit is a ground unit, check the units in the transports instead of normal units 
      int unitCount = (ter.isSeaTerritory && (i == 1 || i == 2 || i == 8)) ? [self sumOfUnitsInTransportsOfType:unitType onTerritory:ter onTeam:team] : [ter sumOfUnitsOfType:unitType onTeam:team]; 

      //Get the number of movable units on this territory 
      int movableCount = 0; 
      if (queue.selectedTerr != nil && queue.selectedTerr != ter) { //This is here to prevent the user from selecting units on another territory while moving units from one territory 
       movableCount = 0; 
      } else if (ter.isSeaTerritory && (i == 1 || i == 2 || i == 8)) { //Units on transports - can be an enemy territory 
       movableCount = [self sumOfUnitsInTransportsOfType:unitType onTerritory:ter onTeam:team]; 
      } else if ([Universal allianceExistsBetweenTeam:team andTeam:ter.currentOwner] || i == 3 || i == 9) { //Other units - only planes can be on an enemy territory 
       movableCount = [ter sumOfMovableUnitsOfType:unitType onTeam:team]; 
      } 

      //See if there are units of this type on this territory on this team 
      if (unitCount > 0) { 

       //Add data to this team's dictionary 
       NSMutableDictionary *unitInfo = [NSMutableDictionary new]; 
       [unitInfo setObject:@(i) forKey:@"UnitTag"]; 
       [unitInfo setObject:unitType forKey:@"UnitType"]; 
       [unitInfo setObject:@(unitCount) forKey:@"Count"]; 
       [unitInfo setObject:@(movableCount) forKey:@"MovableCount"]; 
       [unitInfo setObject:team forKey:@"Team"]; 

       //Add the dictionary 
       [teamArr addObject:unitInfo]; 

       //Increment the counter 
       if (unitsOnCT) { //Must check or it could cause a crash 
        *unitsOnCT += 1; 
       } 
      } 
     } 
    } 

    //Add the team array 
    [moveUnitsView.unitData addObject:teamArr]; 
} 

//Reload the data in the collection view 
[moveUnitsView.collectionV reloadData]; 

而且我cellForItemAtIndexPath的相关代码:

//Dequeue a cell 
    UnitSelectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"UnitSelectionCell" forIndexPath:indexPath]; 

    //Get the team array (at the index of the section), then the unit's data (at the index of the row) 
    NSMutableDictionary *unitData = (moveUnitsView.unitData[indexPath.section])[indexPath.row]; 

    //Get values 
    int unitTag = [[unitData objectForKey:@"UnitTag"] intValue]; 
    int count = [[unitData objectForKey:@"Count"] intValue]; 
    int movableCount = [[unitData objectForKey:@"MovableCount"] intValue]; 
    NSString *unitType = [unitData objectForKey:@"UnitType"]; 

    //Set the cell's values 
    [cell.upB addTarget:self action:@selector(upMoveUnits:) forControlEvents:UIControlEventTouchUpInside]; [cell.upB setTag:unitTag]; 
    [cell.iconB setBackgroundImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[Universal imageNameForUnit:unitType team:[unitData objectForKey:@"Team"]] ofType:nil]] forState:UIControlStateNormal]; 
    [cell.iconB setTitle:[Universal strForExpDisplay:count] forState:UIControlStateNormal]; 
    [Universal adjustTitlePlacementOfB:cell.iconB autosize:FALSE]; //Don't autosize because this is a collection view 
    cell.unitTypeL.text = unitType; 
    cell.unitTypeL.adjustsFontSizeToFitWidth = cell.unitTypeL.adjustsLetterSpacingToFitWidth = TRUE; 

    //Set fonts 
    [Universal setFontForSubviewsOfView:cell]; 

    //Return the cell 
    return cell; 

初始化收集视图时,使用以下方式注册单元:

[moveUnitsView.collectionV registerNib:[UINib nibWithNibName:@"UnitSelectionCell" bundle:nil] forCellWithReuseIdentifier:@"UnitSelectionCell"]; 

编辑#2

@roycable和@亚伦 - brager指出,这可以通过使用imageWithContentsOfFile:引起的。为了验证这一点,我改变cellForItemAtIndexPath这样:

//Dequeue a cell 
    UnitSelectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"UnitSelectionCell" forIndexPath:indexPath]; 

    //Get the team array (at the index of the section), then the unit's data (at the index of the row) 
    NSMutableDictionary *unitData = (moveUnitsView.unitData[indexPath.section])[indexPath.row]; 

    //Get values 
    int unitTag = [[unitData objectForKey:@"UnitTag"] intValue]; 

    [cell setBackgroundColor:[UIColor redColor]]; 
    [cell.upB removeTarget:nil action:NULL forControlEvents:UIControlEventTouchUpInside]; 
    [cell.upB addTarget:self action:@selector(upMoveUnits:) forControlEvents:UIControlEventTouchUpInside]; [cell.upB setTag:unitTag]; 

    //Return the cell 
    return cell; 

奇怪的是,这似乎并没有解决问题。这个功能在字面上并没有做任何强化任务,但它似乎仍然滞后(而时间分析器似乎也证实了这一点)。

在回答Universal代码的请求,而不是张贴代码,我就总结一下吧:

+units刚刚返回17

+unitWithTag:使用switch得到相应之间的数量NSString

+allianceExistsBetweenTeam:看看数组是否包含其中一个字符串

+setFontForSubviewsOfView:是,基本上使用this code

不幸的是递归函数,这似乎不是很重要,因为这个问题仍与过于简单cellForItemAtIndexPath机能发生。

我还实施了@ aaron-brager的新建议。在添加新的之前,我删除了target,并对Time Profiler进行了更改。我没有看到任何东西真的弹出...这是截图。有关UIImage一切都无关紧要这个问题,因为是NSKeyedArchiver,所以唯一的其他东西,真正意义的字符串,数组和字典:

Time Profiler 2

任何及所有的帮助感激 - 我真的需要得到这个固定的(因此赏金)。谢谢!

编辑#3 - 确定解决方案

所以,事实证明,这个问题是不是在任的那些功能。问题在于上面称为更新功能的功能(我们称之为Function A)(我们称之为Function B)。在Function A之后调用Function B,它执行了一项CPU密集型任务。我没有意识到reloadDataat least partially asynchronous这个事实,所以我假设CPU密集型任务和reloadData最终都在争夺CPU时间。我解决我的问题,加入以下权利之前return cell;

if (indexPath.row == [self collectionView:collectionView numberOfItemsInSection:indexPath.section] - 1) { 

     [self performSelector:@selector(performMyCPUIntensiveTask:) withObject:myObject afterDelay:0.1]; 
    } 

我希望这可以帮助别人,将来别人。感谢所有帮助过我的人,我衷心感谢。

+0

您是否使用过[时间分析器](https://developer.apple.com/Library/ios/documentation/AnalysisTools/Reference/Instruments_User_Reference/TimeProfilerInstrument/TimeProfilerInstrument.html)?如果您遇到200毫秒的延迟,您应该在重新加载后看到一个很好的高峰。 – 2014-09-04 00:41:42

+0

你介意给我们提供你所有的示例代码吗?另外,你使用可重复使用的单元格吗? – ArtSabintsev 2014-09-04 00:46:25

+0

感谢您的回复,伙计们。我已经添加了有关您的评论的信息 - 请参阅我的编辑。 – rebello95 2014-09-04 00:57:17

回答

3

一些可能性:

  • 你大概递归函数来设置字体可能是昂贵的。
  • 其他一些Universal功能看起来可能很昂贵。
  • 似乎并没有删除按钮目标,并且每次单元格被重用时,都会向其添加其他目标。
  • imageWithContentsOfFile:跳过缓存;改为使用imageNamed:
+0

+1,接受和+赏金(时间限制让我)为您提供所有帮助,即使问题的根源在于我在另一功能中的愚蠢。谢谢! – rebello95 2014-09-04 02:55:04

10

当您拨打reloadData时,请确保您在主线程中。

NSLog("on main thread: %@", [NSThread isMainThread] ? @"YES" : @"NO"); 

如果你没有再使用GCD发送消息在主线程:

dispatch_async(dispatch_get_main_queue(), ^{ 
    [moveUnitsView.collectionV reloadData]; 
}); 

(不是100%肯定有关语法,我刚才输入到这个浏览器)

+0

刚刚确认这确实在主线程上运行*。不过谢谢。 – rebello95 2014-09-04 02:38:26

+1

对于我在Swift中,调用reloadData需要几秒钟,直到collectionview刷新。这解决了它。 – t0PPy 2016-03-22 22:03:02

+0

这也解决了我的问题。 – RainCast 2016-10-18 05:12:28