web-dev-qa-db-ja.com

警告:UICollectionViewFlowLayoutは、インデックスパス 'abc'のフレームの不一致をキャッシュしました

これは警告を引き起こしているコードです:

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
}

コンソールも出力します:

これは、フローレイアウト「xyz」がUICollectionViewFlowLayoutによって返された属性をコピーせずに変更しているために発生している可能性があります。

この警告を修正するにはどうすればよいですか?

28
Dhruv Goel

これは、フローレイアウト「xyz」がUICollectionViewFlowLayoutによって返された属性をコピーせずに変更しているために発生している可能性があります

そして確かに、それはあなたがやっていることだけです:

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
}

あなたが単に言うならば、私はそれを期待します:

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

または同様の問題はなくなります。

41
matt

上記の素晴らしい答えに加えて。

サンプルコードがSwiftで記述されていることは知っていますが、Objective-Cバージョンを用意すると役立つと思いました。

Objective-Cの場合、コピー機能は浅いコピーのみを実行するため、これは機能しません。これを行う必要があります:

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

読みやすくするために一時変数を追加しました。

41

layoutAttributesForElementsInRectを上書きするときにこの問題が発生しました。 super.layoutAttributesForElementsInRect(rect)配列の各要素を繰り返し処理してcopyを呼び出すことはできなかったため、Foundationクラスに頼ってNSArraycopyItemsを使用することになりました。

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

それは元の質問への答えではありませんが、layoutAttributesForElements(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

@Georgi回答に追加

<NSCopying>は準拠する必要があり、layoutAttributesForItemAtIndexPathへのコピーメッセージコールを追加する必要があります

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

Swift 3!

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

}

func layoutAttributesForItem

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

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

    return currentItemAttributes
}

両方の関数をオーバーライドする場合は、両方の関数でcopyを呼び出す必要があります。

良いコーディング!

2
Lucas Tegliabue

UICollectionViewFlowLayoutをサブクラス化しました。内部layoutAttributesForElementsInRect()この変更を行いました:

から変更する

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

への変更

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