Проблемы с производительностью UICollectionView при выполненииBatchUpdates

Мы пытаемся настроить UICollectionView с пользовательским макетом. Содержимое каждой CollectionViewCell будет изображением. Всего будет несколько тысяч изображений и примерно 140-150 видимых в определенное время. По событию действия потенциально все ячейки будут реорганизованы по положению и размеру. Цель состоит в том, чтобы анимировать все текущие движущиеся события с помощью метода PerformBatchUpdates. Это вызывает огромную задержку, прежде чем все будет анимировано.

На данный момент мы выяснили, что внутри метод layoutAttributesForItemAtIndexPath вызывается для каждой отдельной ячейки (всего несколько тысяч). Кроме того, метод cellForItemAtIndexPath вызывается для большего количества ячеек, чем может быть отображено на экране.

Есть ли какие-либо возможности улучшить производительность анимации?


UICollectionViewFlowLayout по умолчанию не может предложить тот дизайн, который мы хотим реализовать в приложении. Вот часть нашего кода:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
RPDataModel *dm = [RPDataModel sharedInstance]; //Singleton holding some global information
NSArray *plistArray = dm.plistArray; //Array containing the contents of the cells
NSDictionary *dic = plistArray[[indexPath item]];
RPCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CELL" forIndexPath:indexPath];
cell.label.text = [NSString stringWithFormat:@"%@",dic[@"name"]];
cell.layer.borderColor = nil;
cell.layer.borderWidth = 0.0f;
[cell loadAndSetImageInBackgroundWithLocalFilePath:dic[@"path"]]; //custom method realizing asynchronous loading of the image inside of each cell
return cell;
}

layoutAttributesForElementsInRect перебирает все элементы, устанавливая layoutAttributes для всех элементов внутри прямоугольника. Оператор for прерывается, когда первая ячейка выходит за границы, определяемые правым нижним углом прямоугольника:

-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
NSMutableArray* attributes = [NSMutableArray array];
RPDataModel *dm = [RPDataModel sharedInstance];
for (int i = 0; i < dm.cellCount; i++) {
    CGRect cellRect = [self.rp getCell:i]; //self.rp = custom object offering methods to get information about cells; the getCell method returns the rect of a single cell
    if (CGRectIntersectsRect(rect, cellRect)) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:[dm.relevanceArray[i][@"product"] intValue] inSection:0];
        UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
        attribute.size = cellRect.size;
        attribute.center = CGPointMake(cellRect.origin.x + attribute.size.width / 2, cellRect.origin.y + attribute.size.height / 2);
        [attributes addObject:attribute];
    } else if (cellRect.origin.x > rect.origin.x + rect.size.width && cellRect.origin.y > rect.origin.y + rect.size.height) {
        break;
    }
}
return attributes;
}

При изменении макета результаты практически одинаковы, независимо от того, ограничено ли количество ячеек, определенных в layoutAttributesForElementsInRect, или нет. Либо система получает атрибуты макета для всех ячеек, если она не ограничена, либо вызывает метод layoutAttributesForElementAtIndexPath для всех отсутствующих ячеек, если он ограничен. В целом атрибуты для каждой отдельной ячейки каким-то образом используются.

-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
RPDataModel *dm = [RPDataModel sharedInstance];
UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
CGRect cellRect = [self.rp getCell:[dm.indexDictionary[@(indexPath.item)] intValue]];
attribute.size = cellRect.size;
attribute.center = CGPointMake(cellRect.origin.x + attribute.size.width / 2, cellRect.origin.y + attribute.size.height / 2);
return attribute;
}    

person Kevin Wellhöfer    schedule 24.09.2012    source источник
comment
Пожалуйста, опубликуйте свой код из вашего UICollectionViewLayout.   -  person Rob Reuss    schedule 25.09.2012


Ответы (2)


Не видя кода, я предполагаю, что ваш метод layoutAttributesForElementsInRect перебирает все элементы в вашей коллекции, и это, в свою очередь, вызывает чрезмерный вызов других методов. layoutAttributesForElementsInRect дает вам подсказку — то есть CGRect, который он вам передает — о том, для каких элементов вам нужно вызвать layoutAttributesForItemAtIndexPath, с точки зрения того, что находится на экране.

Так что это может быть частью проблемы производительности, то есть настройки вашего пользовательского макета, чтобы он был умным в отношении того, какие элементы он обновляет.

Другие проблемы относятся к производительности анимации в целом. Одна вещь, на которую следует обратить внимание, это если происходит какой-либо композитинг — убедитесь, что ваши изображения непрозрачны. Другое дело, если вы используете тени на своем изображении, их анимация может быть дорогой. Одним из способов улучшить производительность анимации теней является установка значения shadowPath при изменении размера изображения. Если у вас есть тени, дайте мне знать и опубликуйте код для этого.

person Rob Reuss    schedule 24.09.2012
comment
Мы уже просто перебираем все элементы, которые находятся внутри прямоугольника, переданного в layoutAttributesForElementsInRect. Тем не менее система вызывает метод layoutAttributesForItemAtIndexPath для всех ячеек за пределами прямоугольника. В случае с изображениями мы вообще не используем никаких теней, и они уже непрозрачны. Одной из проблем может быть количество просмотров, видимых одновременно (около 140). - person Kevin Wellhöfer; 25.09.2012
comment
Было бы полезно, если бы вы разместили код. Одно из предложений: в целях отладки реализовать одно и то же представление коллекции, используя встроенный UICollectionViewFlowLayout, и присвоить ему параметры, аналогичные тем, которые вы используете в своем пользовательском представлении. Инициируйте события, которые вызывают существенную реорганизацию UICollectionViewFlowLayout, и посмотрите, стала ли анимация лучше. - person Rob Reuss; 26.09.2012
comment
К вашему сведению, Apple наконец опубликовала пример проекта кода для CollectionViews. К сожалению, это до смешного простая реализация — нет пользовательского макета, а это код, который мне действительно нужно увидеть. - person Rob Reuss; 26.09.2012

По-видимому, это вызвано попыткой добавить ячейки в разделы, в которых есть представления заголовков, но в которых уже нет ячеек.

Сообщение об ошибке совершенно бесполезно, и потребовалось несколько часов, чтобы отследить его.

person Gwynne Raskind    schedule 15.01.2013