Здравствуйте! Я использую представление коллекции в своем приложении и заметил, что обновление с использованием reloadData
занимает больше времени, чем ожидалось. В моем представлении коллекции есть 1 section
, и я тестирую его с 5 cell
(каждый из которых имеет 2 кнопки и метку). Я поместил несколько журналов в свой код, чтобы показать, сколько времени на самом деле требуется системе для обновления. Интересно, что журналы показывают, что он обновляется быстрее, чем на самом деле. Например, на устройстве это займет до ~ 0,2 секунды (заметно), но вот логи:
0.007s
С момента вызова reloadData
до момента первого вызова cellForItemAtIndexPath
0.002s
На ячейку для загрузки и возврата
0.041s
С момента вызова reloadData
до момента возврата ячейки №5
В функции cellForItemAtIndexPath
нет ничего особенно интенсивного (в основном просто находит словарь с 3 значениями в NSArray
в row
indexPath
). Даже когда я удалил это и просто вернул ячейку с пустой кнопкой, я увидел такое же поведение.
Кто-нибудь знает, почему это может происходить? Кстати, это происходит только на физическом устройстве (iPad Air). Спасибо!
ИЗМЕНИТЬ №1
Согласно комментарию @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
для возврата NSString
, соответствующего числу между 1-17
+allianceExistsBetweenTeam:
проверяет, содержит ли массив одну из строк
+setFontForSubviewsOfView:
— это рекурсивная функция, которая в основном использует этот код
К сожалению, это не кажется очень актуальным, так как проблема все еще возникает с упрощенной функцией cellForItemAtIndexPath
.
Я также реализовал новые предложения @aaron-brager. Я удалил target
перед добавлением нового и внес изменения в Time Profiler. Я не видел, чтобы что-то действительно выскочило... Вот скриншот. Все, что связано с UIImage
, не имеет отношения к этому вопросу, как и NSKeyedArchiver
, поэтому единственные другие вещи, которые действительно имеют смысл, — это строки, массивы и словари:
Любая помощь очень ценится - мне действительно нужно это исправить (отсюда и щедрость). Спасибо!
Редактировать №3 — Решение найдено
Итак, получается, что проблема была не в одной из этих функций. Проблема заключалась в функции (назовем ее Function A
), которая вызывала функцию обновления выше (назовем ее Function B
). Сразу после того, как Function A
вызвал Function B
, он выполнил задачу с интенсивным использованием ЦП. Я не знал о том, что reloadData
является по крайней мере частично асинхронным, так что я предполагаю, что задача интенсивно использует ЦП, и reloadData
закончилась гонкой за процессорным временем. Я решил свою проблему, добавив следующее прямо перед return cell;
:
if (indexPath.row == [self collectionView:collectionView numberOfItemsInSection:indexPath.section] - 1) {
[self performSelector:@selector(performMyCPUIntensiveTask:) withObject:myObject afterDelay:0.1];
}
Я надеюсь, что это поможет кому-то еще в будущем. Спасибо всем, кто помог, я искренне благодарен.
Universal
методов. - person Aaron Brager   schedule 04.09.2014UICollectionViews
, потому что я загружал изображения с диска в каждыйcellForItemAtIndexPath
, что, я вижу, вы также делаете (imageWithContentsOfFile:
). Если вы можете кэшировать изображения, чтобы они не загружались с диска каждый раз, это может помочь перезагрузке. Если нет, то это должно хотя бы помочь скорости прокрутки в целом. - person roycable   schedule 04.09.2014[Universal units]
? Кроме того, я склонен согласиться с @roycable. Это может быть связано с тем, что вы загружаете изображения с диска. Посмотрите, сможете ли вы закомментировать различные части кодаcellForItemAtIndexPath:
, и посмотрите, какие части вызывают появление всплеска, когда вы нажимаете кнопку перезагрузки. - person ArtSabintsev   schedule 04.09.2014[Universal units]
— очень простая функция, содержащая одну строку:return 17;
. Что касается загрузки изображений, см. мой обновленный вопрос. - person rebello95   schedule 04.09.2014reloadData
(та, что показана выше). Когда я комментирую этот вызов функции, задержка исчезает. Может ли кто-нибудь объяснить, почему это может быть причиной, даже если интенсивная функция вызывается после перезагрузки данных? - person rebello95   schedule 04.09.2014