gpt4 book ai didi

ios - UICollectionView reloadData 看起来很慢/滞后(不是即时的)

转载 作者:可可西里 更新时间:2023-11-01 06:19:10 25 4
gpt4 key购买 nike

您好:我在我的应用程序中使用了集合 View ,我注意到使用 reloadData 刷新所需的时间比预期的要长。 .我的收藏 View 有 1 section ,我正在用 5 cell 测试它s(每个都有 2 个按钮和一个标签)。我将一些日志放入我的代码中,以显示系统实际需要多长时间来刷新。有趣的是,日志表明它的刷新速度比现在快。例如,在设备上,它最多需要约 0.2 秒(明显),但这里是日志:
0.007s从时间 reloadData被叫到时间cellForItemAtIndexPath第一次被称为
0.002s每个单元格加载和返回
0.041s从时间 reloadData被调用到单元格 #5 返回的时间
cellForItemAtIndexPath 中没有什么特别密集的地方函数(基本上只是在 NSArrayindexPathrow 中找到具有 3 个值的字典)。 然而,即使我删除它并返回一个带有空白按钮的单元格,我也看到了相同的行为。

有没有人知道为什么会发生这种情况?顺便说一下,它只发生在物理设备(iPad Air)上。谢谢!

编辑 #1

根据@brian-nickel 的评论,我使用了 Time Profiler 工具,发现它确实每次都出现峰值 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;

初始化集合 View 时,使用以下方法注册单元格:
[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;

奇怪的是,这似乎并没有解决问题。它实际上没有在该功能中执行任何密集型任务,但它似乎仍然滞后(时间分析器似乎证实了这一点)。

响应来自 Universal 的代码请求, 而不是发布代码,我只是总结一下:
+units刚刚返回 17 +unitWithTag:使用 switch返回 NSString对应于 1-17之间的数字
+allianceExistsBetweenTeam:查看数组是否包含其中一个字符串
+setFontForSubviewsOfView:是一个递归函数,基本上使用 this code

不幸的是,这似乎不是很重要,因为问题仍然存在于过于简单化的 cellForItemAtIndexPath 中。功能。

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

Time Profiler 2

非常感谢任何和所有帮助 - 我真的需要解决这个问题(因此是赏金)。谢谢!

编辑 #3 - 确定的解决方案

所以,事实证明问题不在于这两个函数中的任何一个。问题是调用上面的更新函数的函数(我们称之为 Function A )(我们称之为 Function B )。紧随其后 Function AFunction 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];
}

我希望这会在将来对其他人有所帮助。感谢所有帮助过我的人,我衷心感谢。

最佳答案

当您调用 reloadData 时,请确保您在主线程上.

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

如果不是,则使用 GCD 在主线程上发送消息:
dispatch_async(dispatch_get_main_queue(), ^{
[moveUnitsView.collectionV reloadData];
});

(对语法不是 100% 确定,我只是在浏览器中输入了这个)

关于ios - UICollectionView reloadData 看起来很慢/滞后(不是即时的),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25614210/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com