【问题标题】:Warning: UICollectionViewFlowLayout has cached frame mismatch for index path 'abc'警告:UICollectionViewFlowLayout 已缓存索引路径“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 返回的属性而不复制它们。

如何解决此警告?

【问题讨论】:

    标签: ios swift uicollectionview uicollectionviewlayout


    【解决方案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()。但是,您可以在单个布局属性上调用它,然后将它们放入一个数组并返回它。见stackoverflow.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 问题stackoverflow.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
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-08-29
            • 2016-12-06
            • 2021-11-26
            相关资源
            最近更新 更多