Вчера обновился до iOS 8.3 и заметил, что одно из моих приложений стало ужасно тормозить при скроллинге UICollectionView. Лэйаут там наподобие CoverFlow, в ячейках используется Auto Layout, но на iOS 8.2 скроллинг работал быстро.
Запустил профайлер. Оказалось, что в самом тяжёлом стэке вызовов целых 20% времени съедает метод [UICollectionReusableView _preferredLayoutAttributesFittingAttributes:]:
Начал искать, были ли у кого похожие проблемы, и наткнулся на обсуждение в Гитхабе. У них тоже тормозил скроллинг, причём на более ранних версиях iOS, и кто-то предложил добавить такой код в дочерний класс UICollectionViewCell:
- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
return layoutAttributes;
}
Вставил этот код в свою ячейку, и скроллинг снова заработал быстро. Полез смотреть в документацию. Про метод preferredLayoutAttributesFittingAttributes: написано:
The default implementation of this method adjusts the size values to accommodate changes made by a self-sizing cell.
Но мне не нужен был self-sizing. Стал искать дальше, почему начал вызываться метод, пересчитывающий атрибуты лэйаута. В UICollectionViewFlowLayout.h нашёл поле estimatedItemSize:
// defaults to CGSizeZero - setting a non-zero size enables cells
// that self-size via -preferredLayoutAttributesFittingAttributes:
@property (nonatomic) CGSize estimatedItemSize NS_AVAILABLE_IOS(8_0);
Проверил — estimatedItemSize у меня действительно равен нулю, но preferredLayoutAttributesFittingAttributes: всё равно дёргается, причём реализация по умолчанию чаще всего возвращает атрибуты, отличающиеся на несколько десятых от переданных в аргументе.
Получается, что в iOS 8.3 ребята из Apple изменили логику self-sizing для ячеек UICollectionView. В любом случае, согласно документации, этот метод не должен вызываться. Если вдруг у вас тоже начал тормозить скроллинг, попробуйте этот фикс :-)