¿Qué está causando este locking de iOS? UICollectionView recibió attributes de layout para una celda con una ruta de índice que no existe

Estoy trabajando en una aplicación que tiene un UICollectionViewController que se está estrellando en ciertas situaciones misteriosas que son difíciles de reproducir. El logging del locking se ve así:

*** Assertion failure in -[UICollectionViewData validateLayoutInRect:], /SourceCache/UIKit_Sim/UIKit-3318.16.14/UICollectionViewData.m:417 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView received layout attributes for a cell with an index path that does not exist: <NSIndexPath: 0xc000000000008016> {length = 2, path = 0 - 1}' 

Los lockings como este solo parecen haber comenzado a ocurrir en nuestro código una vez que cambiamos al iOS 8 SDK.

¿Por qué está pasando esto?

Nota: Ya sé cuál es la respuesta a la pregunta, pero encontré muy poca información relacionada con este locking en Stack Overflow y el rest de la web. Publicaré la respuesta a continuación. Este error tomó a mi compañero de trabajo y yo tres días para rastrear, así que esperamos que esta publicación le ahorre a mucha otra persona mucho time y frustración. He archivado este error con Apple.

El crash estaba sucediendo en la siguiente situación:

Teníamos un controller de vista de colección que estaba presentando otro controller de vista encima.

Si bien el controller de la vista de la colección ya no era visible, la siguiente secuencia de events ocasionalmente se producía en respuesta a las requestes de background de la aplicación.

  1. [UICollectionView insertItemsAtIndexPaths:] se llamó con 50 elementos en la vista de colección del UICollectionViewController oculto.
  2. [UICollectionView reloadData] se llamó en la vista de colección oculta.
  3. Se produciría una pequeña demora.
  4. El número de elementos en la vista de la colección oculta se configuró en un pequeño número.
  5. [UICollectionView reloadData] se volvió a llamar.
  6. El controller de vista se descartó y se muestra el controller de vista de la colección oculta.

El error de aserción en la class UICollectionViewData UICollectionViewData interna sucedería en el paso 6.

Entonces, la lección es tratar de evitar manipular una vista de colección que no esté visible en la pantalla.

Nuestra solución para este problema fue llamar a [UICollectionView reloadSections:] lugar de [UICollectionView reloadData] en puntos key.

Sospechamos que los efectos de reloadData se reloadData hasta cierto punto en el futuro y, por consiguiente, hay problemas sutiles con la forma en que esto puede interactuar con otras llamadas de método como insertItemsAtIndexPaths , mientras que reloadSections se maneja de inmediato, dejando la vista de recostackción en un mejor estado.

Creemos que no estábamos viendo este comportamiento hasta que comenzamos a build nuestra aplicación para iOS 8.

¡Duerme bien, amigos míos!

Para mí fue la matriz de UICollectionViewLayoutAttribute. Lo uso en UICollectionViewLayout para almacenar el atributo del elemento.

Olvidé vaciarlo en el método prepareLayout .

Entonces, the layoutAttributesForItemAtIndexPath estaba devolviendo valores incorrectos para indexPath, lo que provocó el mismo locking.

Con solo removeAll en el array al comienzo de prepareLayout, está funcionando.

He estado trabajando en este mismo error por un time y creo que he encontrado otra fuente de errores, en iOS 7, pero funciona bien en iOS 8, que causa este mismo error exacto: ¡Diseño automático!

Estoy usando un control que ha embedded UICollectionViews en él, una cuadrícula. Me he dado count al piratear el código para eliminar UICollectionViewLayoutAttributes cuando hay una discordancia con los datos de UICollectionView, causando el locking, que otros controles en mi vista estaban fuera de lugar.

El contenido de mi colección es "estático", cargado en carga y eso es todo, así que no hay posibilidad de cambios sin protección. Nuevamente, esto funciona perfectamente con iOS 8.

Por lo tanto, ¡deshabilité la function de layout automático solo para esta vista y BINGO! Crash desapareció. El Auto-Layout se estaba reproduciendo con el UICollectionSize interno, por lo tanto, el método – (NSArray *) layoutAttributesForElementsInRect: (CGRect) rect devolvía los resultados de la mezcla.

Intenté reloadData, reloadSections, ¡nada funciona pero esto funciona!

Espero que ayude a otra persona a luchar con la exception UIKit con este control.

collectionViewLayout almacena en caching los attributes. En viewwillappear: cree una nueva instancia de collectionViewLayout y asígnela a collectionview.collectionViewLayout. De esta forma, todos los attributes almacenados en caching se purgarán antes de la recarga. Su problema podría resolverse. Funcionó para mí, especialmente cuando está utilizando otras bibliotecas collectionViewLayout.

esto me ayudó:

 cell.collectionView.collectionViewLayout.invalidateLayout() cell.collectionView.reloadData() cell.collectionView.layoutSubviews() 

Xcode 8 – Swift 3

En mi caso, este error fue causado por Autolayout; Tengo una colecciónView incrustada en una UIView que se oculta estableciendo su altura a 0 cuando la colecciónView está vacía y vuelve a 150 cuando necesito mostrar la colecciónView nuevamente.

Me las arreglé para eliminar el error llamando

collectionView.collectionViewLayout.invalitdateLayout ()

antes de ejecutar el código que anima la llamada layoutIfNeeded () en la superView. Es bastante suave ahora.

Espero que pueda ayudar a alguien en el futuro.

 var sponsonetworkingPlaceSummaries: [PlaceSummary] = [] { didSet { if sponsonetworkingPlaceSummaries.isEmpty { self.sponsonetworkingPlacesViewHeight.constant = 0 self.collectionView.collectionViewLayout.invalidateLayout() UIView.animate(withDuration: 1.0, delay: 0, options: .curveEaseInOut, animations: { self.view.layoutIfNeeded() }, completion: nil) } else if self.sponsonetworkingPlacesViewHeight.constant != 150 { self.sponsonetworkingPlacesViewHeight.constant = 150 UIView.animate(withDuration: 1.0, delay: 0, options: .curveEaseInOut, animations: { self.view.layoutIfNeeded() }, completion: nil) } } 

Me encontré con el mismo problema. En mi situación, tengo 2 UICollectionView en una pantalla y tienen el mismo tamaño.

Entonces, reutilizo el mismo UICollectionViewLayout como parámetro inicial <- Ese es el problema.

2 UICollectionView debería usar un parámetro UICollectionViewLayout diferente. Entonces, solo otro nuevo UICollectionViewLayout para la segunda UICollectionView.

Asegúrese de que su origen de datos y delegates para collectionview estén conectados al controller de vista correcto. Una vez tuve este locking, ya que accidentalmente descarté cambios en mi Main.Storyboard y debido a qué fuente de datos y delegates dejaron desconectados

Estaba recibiendo el mismo error, pero estaba sucediendo de forma bastante aleatoria, ya que no podía volver a crear el error de forma coherente. Estaba usando un customLayout donde estaba configurando los attributes de los elementos manualmente. Haría una cosa en mi iPhone real que lo bloquearía, pero en el simulador xCode funcionaría. Lo que terminó solucionando mi problema fue usar collectionView.reloadData () en lugar de collectionView.reloadSections ([mySectionNum]). No tengo ni idea de por qué funcionaba a veces y no a otras. Parece que debería haberse estrellado todo el time, pero no fue así. Tampoco tengo idea de por qué funciona este arreglo.

Para mí, era algo relacionado con la respuesta de @ Drew (mi vista de la colección estaba fuera de la pantalla). Estaba manipulando una restricción de altura de collectionView para queuepsarla cuando no hay datos. Causo este locking (¡a veces!). Coloqué collectionView dentro de otra vista y volví a asignar @IBOutlet a la restricción de altura de esta nueva vista. E hizo que la altura de la colecciónView sea constante. Crash se ha ido para siempre!