これは警告を引き起こしているコードです:
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によって返された属性をコピーせずに変更しているために発生している可能性があります。
この警告を修正するにはどうすればよいですか?
これは、フローレイアウト「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の場合、コピー機能は浅いコピーのみを実行するため、これは機能しません。これを行う必要があります:
NSArray * original = [super layoutAttributesForElementsInRect:rect];
NSArray * attributes = [[NSArray alloc] initWithArray:original copyItems:YES];
読みやすくするために一時変数を追加しました。
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
}
それは元の質問への答えではありませんが、layoutAttributesForElements(rect:CGRect)(Swift 3.0)に役立ちます:
let safeAttributes = super.layoutAttributesForElements(in: rect)?.map { $0.copy() as! UICollectionViewLayoutAttributes }
safeAttributes?.forEach { /* do something with attributes*/ }
@Georgi回答に追加
<NSCopying>
は準拠する必要があり、layoutAttributesForItemAtIndexPath
へのコピーメッセージコールを追加する必要があります
UICollectionViewLayoutAttributes* attributes = [[super layoutAttributesForItemAtIndexPath:indexPath] copy];
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
}
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を呼び出す必要があります。
良いコーディング!
UICollectionViewFlowLayout
をサブクラス化しました。内部layoutAttributesForElementsInRect()
この変更を行いました:
から変更する
guard let attributesForItem: UICollectionViewLayoutAttributes = self.layoutAttributesForItemAtIndexPath(indexPath) else {
return
}
への変更
guard let attributesForItem = self.layoutAttributesForItemAtIndexPath(indexPath)?.copy() as? UICollectionViewLayoutAttributes else {
return
}