web-dev-qa-db-fra.com

Avertissement: UICollectionViewFlowLayout a mis en cache une incompatibilité de cadre pour le chemin d'index 'abc'

C'est le code à l'origine de l'avertissement:

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 imprime également:

Cela est probablement dû au fait que la présentation de flux "xyz" modifie les attributs renvoyés par UICollectionViewFlowLayout sans les copier.

Comment puis-je résoudre cet avertissement?

27
Dhruv Goel

Cela est probablement dû au fait que la présentation de flux "xyz" modifie les attributs renvoyés par UICollectionViewFlowLayout sans les copier

Et bien sûr, c'est ce que vous faites:

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
}

J'espère que si vous dites simplement:

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

ou similaire, le problème disparaîtra.

41
matt

En plus de la bonne réponse ci-dessus.

Je sais que l’exemple de code est écrit en Swift, mais j’ai pensé qu’il pourrait être utile d’avoir la version Objective-C.

Pour Objective-C, cela ne fonctionnera pas, car la fonction de copie effectue uniquement une copie superficielle. Vous devrez faire ceci:

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

J'ai ajouté une variable temporaire pour la lisibilité.

41
Georgi Boyadzhiev

J'ai eu ce problème en surchargeant layoutAttributesForElementsInRect. Itérer sur chaque élément du tableau super.layoutAttributesForElementsInRect(rect) et la copie appelante ne fonctionnant pas pour moi, je me suis donc retourné vers les classes Foundation et j'ai utilisé NSArray 's copyItems:

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
}
16
JAL

Ce n'est pas la réponse à la question initiale, mais peut aider pour layoutAttributesForElements (in rect: CGRect) (Swift 3.0): 

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

Ajout à @Georgi answer

<NSCopying> doit être conforme et ajouter un appel de message de copie à layoutAttributesForItemAtIndexPath

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

Réponse mise à jour pour Swift 3!

pour 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

}

pour 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 vous annulez les deux fonctions, vous devez appeler la copie pour les deux

Bon codage!

2
Lucas Tegliabue

J'ai sous-classé UICollectionViewFlowLayout. Dans layoutAttributesForElementsInRect() j'ai fait ce changement:

changer de

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

changer à

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