[英]UICollectionView in UICollectionViewCell slow/laggy scrolling
[英]UICollectionView reloadData seems slow/laggy (not instantaneous)
您好:我正在我的应用程序中使用集合视图,并且我注意到使用reloadData
刷新所需的时间比预期的要长。 我的集合视图有1个section
,我正在测试它有5个cell
(每个cell
有2个按钮和一个标签)。 我将一些日志放入我的代码中,以显示系统实际需要刷新多长时间。 有趣的是,日志表明它的刷新速度比它快。 例如,在设备上,它将花费约0.2秒(明显),但这里是日志:
0.007s
从调用reloadData
到第一次调用时,将调用cellForItemAtIndexPath
每个单元加载0.002s
并返回
0.041s
从调用reloadData
到返回单元格#5的时间
在cellForItemAtIndexPath
函数中没有任何特别密集的cellForItemAtIndexPath
(基本上只是在indexPath
row
的NSArray
中找到一个包含3个值的字典)。 即使我删除了这个并且刚刚返回一个带有空白按钮的单元格,我也看到了相同的行为。
有没有人知道为什么会发生这种情况? 顺便提一下,它只发生在物理设备(iPad Air)上。 谢谢!
编辑#1
根据Per @ brian-nickel的评论,我使用了Time Profiler工具,发现每次调用reloadData
确实会出现峰值。 这是一个截图:
@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和@ aaron-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;
奇怪的是,这似乎并没有解决问题。 它实际上并没有在该功能中执行密集任务,但它似乎仍然滞后(Time Profiler似乎证实了这一点)。
为了响应来自Universal
代码请求,我只是简单地总结一下代码:
+units
只返回17
+unitWithTag:
使用switch
返回对应于1-17
之间的数字的NSString
+allianceExistsBetweenTeam:
查看数组是否包含其中一个字符串
+setFontForSubviewsOfView:
是一个基本上使用此代码的递归函数
不幸的是,这似乎不太相关,因为过度简化的cellForItemAtIndexPath
函数仍然会出现问题。
我还实施了@ aaron-brager的新建议。 我在添加新target
之前删除了target
,然后对Time Profiler进行了更改。 我没有看到任何真正的弹出...这是截图。 与UIImage
相关的一切都与NSKeyedArchiver
这个问题无关,所以唯一真正有用的东西是字符串,数组和字典:
非常感谢任何和所有的帮助 - 我真的需要得到这个固定(因此赏金)。 谢谢!
编辑#3 - 确定解决方案
因此,事实证明问题不在于这些功能中的任何一个。 问题是函数(让我们称之为Function A
)调用上面的更新函数(让我们称之为Function B
)。 在Function A
称为Function B
,它执行了CPU密集型任务。 我不知道reloadData
至少部分是异步的 ,所以我假设CPU密集型任务和reloadData
最终争夺CPU时间。 我通过在return cell;
之前添加以下内容来解决我的问题return cell;
:
if (indexPath.row == [self collectionView:collectionView numberOfItemsInSection:indexPath.section] - 1) {
[self performSelector:@selector(performMyCPUIntensiveTask:) withObject:myObject afterDelay:0.1];
}
我希望将来可以帮助别人。 感谢所有帮助过的人,我真诚地感谢它。
调用reloadData
时,请确保您在主线程上。
NSLog("on main thread: %@", [NSThread isMainThread] ? @"YES" : @"NO");
如果你不是那么使用GCD在主线程上发送消息:
dispatch_async(dispatch_get_main_queue(), ^{
[moveUnitsView.collectionV reloadData];
});
(不是100%确定语法,我只是在浏览器中输入)
一些可能性:
Universal
功能看起来可能很昂贵。 imageWithContentsOfFile:
跳过缓存; 使用imageNamed:
代替。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.