it-swarm.com.de

Warnung: UICollectionViewFlowLayout hat Frame-Konflikt für den Indexpfad 'abc' im Cache

Dies ist der Code, der die Warnung verursacht:

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
}

Die Konsole druckt auch:

Dies ist wahrscheinlich der Fall, weil das Flusslayout "xyz" die von UICollectionViewFlowLayout zurückgegebenen Attribute ändert, ohne sie zu kopieren.

Wie löse ich diese Warnung?

27
Dhruv Goel

Dies ist wahrscheinlich der Fall, weil das Flusslayout "xyz" die von UICollectionViewFlowLayout zurückgegebenen Attribute ändert, ohne sie zu kopieren

Und genau das tun Sie gerade:

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
}

Ich erwarte das, wenn Sie einfach sagen:

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

oder ähnliches wird das Problem verschwinden.

41
matt

Neben der tollen Antwort oben.

Ich weiß, dass der Beispielcode in Swift geschrieben ist, aber ich dachte, dass es hilfreich sein kann, die Objective-C-Version zu haben.

Bei Objective-C funktioniert dies nicht, da die Kopierfunktion nur eine flache Kopie ausführt. Sie müssen das tun:

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

Ich habe eine temporäre Variable zur besseren Lesbarkeit hinzugefügt.

41

Ich hatte dieses Problem beim Überschreiben von layoutAttributesForElementsInRect. Die Iteration durch jedes Element im super.layoutAttributesForElementsInRect(rect)-Array und die aufrufende Kopie funktionierten nicht für mich. Daher fiel ich auf Foundation-Klassen zurück und verwendete NSArrays 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

Es ist nicht die Antwort auf die ursprüngliche Frage, kann jedoch für layoutAttributesForElements (in rect: CGRect) (Swift 3.0) hilfreich sein: 

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

Hinzufügen zu @Georgis Antwort

<NSCopying> muss konform sein und den Aufruf der Kopienachricht zu layoutAttributesForItemAtIndexPath hinzufügen.

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

Aktualisierte Antwort für Swift 3!

für 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

}

für func layoutAttributesForItem

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {

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

    return currentItemAttributes
}

Wenn Sie beide Funktionen überschreiben, müssen Sie copy für beide Funktionen aufrufen!

Gute Codierung!

2
Lucas Tegliabue

Ich habe UICollectionViewFlowLayout subclassed. In layoutAttributesForElementsInRect() habe ich diese Änderung vorgenommen:

wechsel von

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

ändern

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