警告:UICollectionViewFlowLayout缓存了索引路径'abc'的帧不匹配

时间:2015-07-20 02:42:27

标签: ios swift uicollectionview uicollectionviewlayout

这是导致警告的代码:

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

如何修复此警告?

7 个答案:

答案 0 :(得分:41)

  

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

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

答案 1 :(得分:41)

除了上面的好答案。

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

对于Objective-C,这不会起作用,因为复制功能只做一个浅拷贝。你必须这样做:

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

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

答案 2 :(得分:18)

覆盖layoutAttributesForElementsInRect时出现此问题。迭代super.layoutAttributesForElementsInRect(rect)数组中的每个元素并调用副本并不适合我,所以我最终回到基础课并使用NSArray' s 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
}

答案 3 :(得分:6)

添加@Georgi回答

必须符合

<NSCopying>并将复制邮件调用添加到layoutAttributesForItemAtIndexPath

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

答案 4 :(得分:6)

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

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

答案 5 :(得分:2)

更新了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

}

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!

良好的编码!

答案 6 :(得分:0)

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

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

更改为

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