it-swarm.com.ru

ошибка iOS 10: UICollectionView получил атрибуты макета для ячейки с индексным путем, который не существует

Запустив мое приложение на устройстве с iOS 10, я получаю эту ошибку:

UICollectionView получил атрибуты макета для ячейки с индексным путем, который не существует

В iOS 8 и 9 работает отлично. Я занимался исследованиями и обнаружил, что это связано с недействительностью макета представления коллекции. Я пытался реализовать это решение безуспешно, поэтому я хотел бы попросить о прямой помощи. Это мой иерархический взгляд:

->Table view 
    ->Each cell of table is a custom collection view [GitHub Repo][1]
        ->Each item of collection view has another collection view

То, что я пытался это вставить

    [self.collectionView.collectionViewLayout invalidateLayout];

В

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView

обоих видов коллекции. 

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

Кто-нибудь может дать мне несколько указаний?

60
cmacera

Это случилось со мной, когда количество ячеек в collectionView изменилось. Оказывается, мне не хватало invalidateLayout после вызова reloadData. После добавления я больше не испытывал сбоев. Apple внесла некоторые изменения в коллекцию Views в iOS10. Я думаю, что это причина, почему мы не испытываем ту же проблему на старых версиях.

Вот мой окончательный код:

[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];
118
Katrin Annuk

Если у вас есть пользовательский макет, не забудьте очистить кеш (UICollectionViewLayoutAttributes) при переопределении функции prepare.

    override func prepare() {
       super.prepare()
       cache.removeAll()
    }
35
ArturC

Я также столкнулся с этой проблемой с двумя collectionViews в одном представлении, потому что я добавил один и тот же UICollectionViewFlowLayout в обе коллекции: 

let layout = UICollectionViewFlowLayout()
collectionView1.collectionViewLayout = layout
collectionView2.collectionViewLayout = layout

Конечно, происходит сбой при перезагрузке данных при изменении данных collectionView1. Если бы это могло помочь кому-то.

15
Aximem

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

 UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
 layout.estimatedItemSize = CGSizeMake(60, 25);
 layout.itemSize = UICollectionViewFlowLayoutAutomaticSize;             
 self.collectionView.collectionViewLayout = layout;

Я решаю эту проблему, заменив

[self.collectionView reloadData];

в

[self.collectionView reloadSections:indexSet];
4
Andrey

Не всегда лучше каждый раз перезагружать данные (вы должны использовать insertItems, deleteItems и даже reloadSections). Но ... сказав, что в некоторых случаях это действительно так, вы можете сделать это:

collectionView.dataSource = nil

collectionView.delegate = nil

/*... All changes here. ... */

collectionView.dataSource = self

collectionView.delegate = self

collectionView.reloadData()
3
Kevin Bel

Вызов invalidateLayout в моем случае не предотвратил сбой. (Это работало, если количество элементов в представлении коллекции увеличивалось, но не уменьшалось). Контекст: у меня есть UICollectionView внутри UITableViewCell, и когда ячейка таблицы используется повторно, я сбрасываю делегатов collectionView. Я исправил проблему не путем аннулирования кэша, а путем РЕКРЕАЦИИ объекта макета каждый раз, когда я сбрасывал делегат, затем вызывал reloadData ():

foo.dataSource = newDataSource
foo.delegate = newDelegate
foo.fixLayoutBug()
foo.reloadData()

func fixLayoutBug() {
    let oldLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let newLayout = UICollectionViewFlowLayout()
    newLayout.estimatedItemSize = oldLayout.estimatedItemSize
    newLayout.footerReferenceSize = oldLayout.footerReferenceSize
    newLayout.headerReferenceSize = oldLayout.headerReferenceSize
    newLayout.itemSize = oldLayout.itemSize
    newLayout.minimumInteritemSpacing = oldLayout.minimumInteritemSpacing
    newLayout.minimumLineSpacing = oldLayout.minimumLineSpacing
    newLayout.scrollDirection = oldLayout.scrollDirection
    newLayout.sectionFootersPinToVisibleBounds = oldLayout.sectionFootersPinToVisibleBounds
    newLayout.sectionHeadersPinToVisibleBounds = oldLayout.sectionHeadersPinToVisibleBounds
    newLayout.sectionInset = oldLayout.sectionInset
    newLayout.sectionInsetReference = oldLayout.sectionInsetReference
    collectionViewLayout = newLayout
}
3
Nick Kallen

Ответ @ Katrin очень помог, но я мог бы достичь еще лучших результатов, добавив еще одну строчку:

collectionView.reloadData()
collectionView.collectionViewLayout.invalidateLayout()
collectionView.layoutSubviews() // <-- here it is :)

Я не могу сейчас сказать, смогу ли я воспроизвести аварию с этой линией или нет, но я думаю, что была одна ... Итак, все еще не серебряная пуля, но что-то.

3
m8labs

В моем случае я менял константу NSlayoutConstraint 

self.collectionViewContacts.collectionViewLayout.invalidateLayout()

            UIView.animate(withDuration: 0.3) {
                self.view.layoutIfNeeded()
            }


            self.collectionViewContacts.reloadData()

решил проблему

2
jeff ayan

Если вы хотите сохранить свою позицию прокрутки и исправить ошибку, вы можете использовать это:

collectionView.reloadData()
let context = collectionView.collectionViewLayout.invalidationContext(forBoundsChange: collectionView.bounds)
context.contentOffsetAdjustment = CGPoint.zero
collectionView.collectionViewLayout.invalidateLayout(with: context)
1
Mati Bot

Сброс макета UICollectionView решил проблему для меня:

let layout = UICollectionViewFlowLayout()
collectionView?.collectionViewLayout = layout
1
krlb

В моем случае я менял константу NSLayoutConstraint, ни одно из вышеуказанных решений не помогло мне. спасибо @jeff ayan, чей ответ дал мне подсказку. Я решил проблему с этим кодом

override func prepareForReuse() {
    super.prepareForReuse()
    imagesCollectionHeight.constant = 100 // changing collectionview height constant
    imageContainerWidth.constant = 100  //changing width constant of some view
    self.layoutIfNeeded() // this line did the trick for me
}

Надеюсь, это поможет кому-то

0
Gulfam Khan

Следующее сделало это для меня:

[self.collectionView reloadData];
[self.collectionView layoutIfNeeded];

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

0
Javier Alzueta

Это также случилось со мной, но это произошло потому, что мой UICollectionViewDataSource изменился, и я не вызвал -[UICollectionView reloadData]. В моем случае у меня была следующая структура данных:

struct Bar { let name: String }
struct Foo { let name: String; let bars: [Bar] }

У меня было два UICollectionViews: один для Foos и один для Bars. В моем -collectionView:didSelectItemAtIndexPath: у меня было следующее:

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
  if (collectionView == self.fooCollectionView) {
    self.selectedFoo = self.foos[indexPath.row];
    [self.barCollectionView reloadData];
    self.fooCollectionView.hidden = YES;
    self.barCollectionView.hidden = NO;
  } else if (collectionView == self.barCollectionView) {
    // do some stuff with the selected bar

    self.selectedFoo = nil;
    // This -reloadData call fixed my error. I thought I didn't
    // need it since my UICollectionView was hidden
    [self.barCollectionView reloadData];
    self.barCollectionView.hidden = YES;
    self.fooCollectionView.hidden = NO;
  }
}

Без вызова -reloadData я бы увидел сбой при повороте устройства.

0
Heath Borders

У меня тоже была эта проблема. В моем случае к представлению коллекции был применен пользовательский параметр UICollectionViewLayout, и проблема заключалась в том, что он имел устаревшие данные о количестве ячеек, которые должны отображаться. Это определенно то, что вы можете проверить, когда увидите UICollectionView received layout attributes for a cell with an index path that does not exist

0
Trev14

Потратив два дня времени, приведенный ниже код решил проблему. Перед загрузкой коллекции напишите приведенный ниже код.

let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
collecView.collectionViewLayout = flowLayout 
collecView.delegate = self
collecView.dataSource = self
collecView.reloadData()

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

flowLayout.itemSize = CGSize(width: 92, height: 100)

С помощью приведенной выше строки кода вы можете настроить макет ячейки.

Надеюсь, это кому-нибудь поможет.

0
Arshad Shaik

Мне удалось решить эту проблему путем воссоздания collectionViewLayout перед вызовом reloadData()

Вероятно, проблема была связана с тем, что у меня был отдельный экземпляр для dataSource (т. Е. Не контроллер представления, содержащий collectionView), и при обмене источником данных может произойти сбой.

0
ullstrm