Advertencia: UICollectionViewFlowLayout tiene desajuste de marco en caching para la ruta de índice 'abc'

Este es el código que causa la advertencia:

private override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { let attributes = super.layoutAttributesForItemAtIndexPath(indexPath) let distance = CGRectGetMidX(attributes!.frame) - self.midX; var transform = CATransform3DIdentity; transform = CATransform3DTranslate(transform, -distance, 0, -self.width); attributes!.transform3D = CATransform3DIdentity; return attributes } 

La console también imprime:

Es probable que esto ocurra porque el layout de flujo "xyz" está modificando los attributes devueltos por UICollectionViewFlowLayout sin copyrlos.

¿Cómo soluciono esta advertencia?

Es probable que esto ocurra porque el layout de flujo "xyz" está modificando los attributes devueltos por UICollectionViewFlowLayout sin copyrlos

Y eso es exactamente lo que estás haciendo:

 private override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { let attributes = super.layoutAttributesForItemAtIndexPath(indexPath) let distance = CGRectGetMidX(attributes!.frame) - self.midX; var transform = CATransform3DIdentity; transform = CATransform3DTranslate(transform, -distance, 0, -self.width); attributes!.transform3D = CATransform3DIdentity; return attributes } 

Espero que si simplemente dices:

 let attributes = super.layoutAttributesForItemAtIndexPath(indexPath).copy() as! UICollectionViewLayoutAttributes 

o similar, el problema desaparecerá.

Además de la gran respuesta anterior.

Sé que el código de ejemplo está escrito de manera rápida, pero pensé que podría ser útil tener la versión de Objective-C.

Para Objective-C, esto no funcionará, ya que la function de copy hace solo una copy superficial. Tendrás que hacer esto:

 NSArray * original = [super layoutAttributesForElementsInRect:rect]; NSArray * attributes = [[NSArray alloc] initWithArray:original copyItems:YES]; 

He agregado una variable temporal para la legibilidad.

Tuve este problema al replace layoutAttributesForElementsInRect . La repetición de cada elemento en la super.layoutAttributesForElementsInRect(rect) y la copy de llamada no funcionaban para mí, así que terminé cayendo en las classs de Foundation y usando copyItems NSArray :

 override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? { // unwrap super's attributes guard let superArray = super.layoutAttributesForElementsInRect(rect) else { return nil } // copy items guard let attributes = NSArray(array: superArray, copyItems: true) as? [UICollectionViewLayoutAttributes] else { return nil } // modify attributes return attributes } 

Agregando a @Georgi respuesta

<NSCopying> debe conformarse y agregar una llamada de post de copy a layoutAttributesForItemAtIndexPath

 UICollectionViewLayoutAttributes* attributes = [[super layoutAttributesForItemAtIndexPath:indexPath] copy]; 

No es la respuesta a la pregunta original, pero puede ayudar a layoutAttributesForElements (en rect: CGRect) (Swift 3.0):

 let safeAttributes = super.layoutAttributesForElements(in: rect)?.map { $0.copy() as! UICollectionViewLayoutAttributes } safeAttributes?.forEach { /* do something with attributes*/ } 

¡Respuesta actualizada para Swift 3!

para func layoutAttributesForElements

 override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { guard let attributes = super.layoutAttributesForElements(in: rect) else { return nil } guard let attributesToReturn = attributes.map( { $0.copy() }) as? [UICollectionViewLayoutAttributes] else { return nil } return attributesToReturn } 

para func layoutAttributesForItem

 override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { guard let currentItemAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes else { return nil } return currentItemAttributes } 

¡Si anula ambas funciones, debe llamar a copyr en ambas funciones!

Buena encoding

He subclassado UICollectionViewFlowLayout . Dentro de layoutAttributesForElementsInRect() hice este cambio:

cambiar de

 guard let attributesForItem: UICollectionViewLayoutAttributes = self.layoutAttributesForItemAtIndexPath(indexPath) else { return } 

cambiar a

 guard let attributesForItem = self.layoutAttributesForItemAtIndexPath(indexPath)?.copy() as? UICollectionViewLayoutAttributes else { return }