警告:UICollectionViewFlowLayoutcaching了索引path'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 } 

控制台还打印:

这可能是因为stream布局“xyz”正在修改由UICollectionViewFlowLayout返回的属性而不复制它们。

我如何解决这个警告?

这可能是因为stream布局“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编写的,但我认为有Objective-C版本会有所帮助。

对于Objective-C,这将不起作用,因为复制function只做浅拷贝。 你将不得不这样做:

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

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

当重写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 } 

添加到@Georgi的答案

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

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

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

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

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

如果你重写这两个函数,你必须调用复制两个函数!

好的编码!

我已经分类了UICollectionViewFlowLayout 。 里面layoutAttributesForElementsInRect()我做了这个改变:

从…改变

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

改成

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