警告:UICollectionViewFlowLayout 已缓存索引路径“abc”的帧不匹配

Posted

技术标签:

【中文标题】警告:UICollectionViewFlowLayout 已缓存索引路径“abc”的帧不匹配【英文标题】:Warning: UICollectionViewFlowLayout has cached frame mismatch for index path 'abc' 【发布时间】:2015-07-20 02:42:26 【问题描述】:

这是导致警告的代码:

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 返回的属性而不复制它们。

如何解决此警告?

【问题讨论】:

【参考方案1】:

这可能是因为流布局“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

或类似的,问题就会消失。

【讨论】:

在 Swift 2 中,您不能在 super.layoutAttributesForItemAtIndexPath 上调用 copy()。但是,您可以在单个布局属性上调用它,然后将它们放入一个数组并返回它。见***.com/a/31508225/1259702 @TrevorAlyn 是的,你可以。这是我这样做的一个例子。 github.com/mattneub/Programming-ios-Book-Examples/blob/… 我在回答中给出的代码是 Swift 2 并且工作正常。 @matt:糟糕——我试图在 layoutAttributesForElementsInRect 上调用 copy(),而不是 layoutAttributesForItemAtIndexPath。但是当我尝试这样做时,Xcode 给了我一个“没有成员副本”错误: var attributes = super.layoutAttributesForElementsInRect(rect).copy() @TrevorAlyn 如果你不复制它,它会给你同样的错误吗? 不。幸运的是,我可以复制各个属性,如下所示: attributesCopy.append(attributes![0].copy() as!UICollectionViewLayoutAttributes)【参考方案2】:

除了上面的好答案。

我知道示例代码是用 swift 编写的,但我认为拥有 Objective-C 版本会有所帮助。

对于 Objective-C,这是行不通的,因为 copy 函数只做一个浅拷贝。你必须这样做:

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

为了便于阅读,我添加了一个临时变量。

【讨论】:

另外:当您使用属性数组时,我的答案很方便,如果您只想获取特定 indexPath 的属性,请参阅 Ayman Ibrahim 的答案【参考方案3】:

我在覆盖 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

【讨论】:

感谢您发布此内容,即使有另一个答案。我正在遍历数组中的每个元素并进行复制。也没有为我工作。感谢您发布此解决方案。 @JAL,如何将属性附加到它。因为它是一个 NSArray @Ranjit 将 NSArray 转换为 Swift 数组,就像我对 attributes 变量所做的那样 @JAL,我解决了复制问题,但我还面临一个问题,我在这里创建了一个 SO 问题***.com/questions/38146913/…【参考方案4】:

这不是原始问题的答案,但可以帮助 layoutAttributesForElements(in rect: CGRect) (Swift 3.0):

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

【讨论】:

【参考方案5】:

添加到@Georgi 答案

<NSCopying> 必须符合并添加复制消息调用到layoutAttributesForItemAtIndexPath

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

【讨论】:

【参考方案6】:

更新了 Swift 3 的响应!

for 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


for 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!

编码不错!

【讨论】:

【参考方案7】:

我已经继承了UICollectionViewFlowLayout。在layoutAttributesForElementsInRect() 里面我做了这个改变:

改变

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

改成

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

【讨论】:

以上是关于警告:UICollectionViewFlowLayout 已缓存索引路径“abc”的帧不匹配的主要内容,如果未能解决你的问题,请参考以下文章

警告执行已完成,带有警告存储过程

怎么忽略KEIL的警告

IOS警告消除

Quick.db unwarn 命令取消警告成员中的所有警告

java程序中很多警告,如何修改掉?

将特定级别的所有警告视为错误,而不是下一级的警告