警告: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 类并使用 NSArray
的 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
【讨论】:
感谢您发布此内容,即使有另一个答案。我正在遍历数组中的每个元素并进行复制。也没有为我工作。感谢您发布此解决方案。 @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”的帧不匹配的主要内容,如果未能解决你的问题,请参考以下文章