performBatchUpdates()を使用してコレクションビューを更新しています。ここでは、完全な更新を行っています。つまり、そこにあったものをすべて削除し、すべてを再挿入しています。バッチ更新は、NSMutableArray
(bingDataItems
)に接続されているObserverの一部として行われます。
cellItemsは、コレクションビューに挿入されている、またはこれから挿入されるアイテムを含む配列です。
これがコードです:
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
cultARunner *_cultARunner = [cultARunner getInstance];
if ( [[_cultARunner bingDataItems] count] ) {
[self.collectionView reloadData];
[[self collectionView] performBatchUpdates: ^{
int itemSize = [cellItems count];
NSMutableArray *arrayWithIndexPaths = [NSMutableArray array];
// first delete the old stuff
if (itemSize == 0) {
[arrayWithIndexPaths addObject: [NSIndexPath indexPathForRow: 0 inSection: 0]];
}
else {
for( int i = 0; i < cellItems.count; i++ ) {
[arrayWithIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
}
[cellItems removeAllObjects];
if(itemSize) {
[self.collectionView deleteItemsAtIndexPaths:arrayWithIndexPaths];
}
// insert the new stuff
arrayWithIndexPaths = [NSMutableArray array];
cellItems = [_cultARunner bingDataItems];
if ([cellItems count] == 0) {
[arrayWithIndexPaths addObject: [NSIndexPath indexPathForRow: 0 inSection: 0]];
}
else {
for( int i = 0; i < [cellItems count]; i++ ) {
[arrayWithIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
}
[self.collectionView insertItemsAtIndexPaths:arrayWithIndexPaths];
}
completion:nil];
}
}
私はこのエラーを受け取りますが、いつもではありません(なぜですか?)
2012-12-16 13:17:59.789 [16807:19703] *** Assertion failure in -[UICollectionViewData indexPathForItemAtGlobalIndex:], /SourceCache/UIKit_Sim/UIKit-2372/UICollectionViewData.m:442
2012-12-16 13:17:59.790 [16807:19703] DEBUG: request for index path for global index 1342177227 when there are only 53 items in the collection view
ここで同じ問題に言及している唯一のスレッドをチェックしました: ICollectionView Assertion failure ですが、明確ではありません。つまり、performBatchUpdates()
ブロックで[collectionview reloadData]
を実行することはお勧めできません。
ここで何がうまくいかないのかについての提案はありますか?
最後に! OK、このクラッシュの原因は次のとおりです。
前述のように、コレクションビューにカスタムスタイルのセクションヘッダーを提供するために、補足ビューを作成していました。
問題はこれです。補足ビューのindexPathは、コレクション内の現存するセルのindexPathに対応している必要があります。補足ビューのインデックスパスに対応する通常のセルがない場合、アプリケーションはクラッシュします。コレクションビューは、更新手順中になんらかの理由で補足ビューのセルの情報を取得しようとすると思います。見つからない場合はクラッシュします。
うまくいけば、これもあなたの問題を解決するでしょう!
これは、このクラッシュに対する適切な回避策です。
補足ビューのそれぞれは、特定のインデックスパスに関連付けられています。そのインデックスパスにセルがない場合(初期ロード、行の削除など)、レイアウトのデリゲートを介して補助ビューの高さ0を返します。
したがって、フローレイアウトの場合、UICollectionViewDelegateFlowLayoutの実装
(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
メソッド(およびフッターを使用している場合は対応するフッターメソッド)と次のロジック
if ( you-have-a-cell-at-the-row-for-this-section )
return myNormalHeaderSize;
else return CGSizeMake( 0,0 );
お役に立てれば!
reloadData
を使用する目的はすべて、変更をアニメーション化することなので、performBatchUpdates
は機能しません。 reloadData
を使用する場合、データは更新されますが、アニメーションは更新されません。
したがって、「performBatchUpdates
をreloadData
で置き換える」という提案は、「やろうとしていることをあきらめる」と言っています。
申し訳ありませんが、すばらしいアニメーションの更新を試みている間にこのエラーが何度も表示され、モデルが100%正しいので、イライラしています。完全にソリューション。
私の意見では、コレクションビューはまだバグがあり、複雑なアニメーションの更新を行うことはできても、それを行うことはできません。これは以前はテーブルビューでも同じでしたが、現在はかなり安定しています(ただし時間がかかりました)。
//編集(2013年9月1日)報告されたバグは現在クローズされているため、この問題はAppleによってすでに解決されているようです。
私も同じ問題を抱えています。
私はいくつかのバリエーションを試しましたが、動作するように見える最後のものは[self.collectionView reloadData]
、 どこ "self.collectionView"
は、コレクションビューの名前です。
「UICollectionViewクラスリファレンス」から直接、アイテムの挿入、移動、削除のメソッドを試しました。
これらは最初、アイテムをあるセクションから別のセクションに「移動」するために使用されました。
deleteItemsAtIndexPaths:
insertItemsAtIndexPaths:
次に、moveItemAtIndexPath:toIndexPath:
。
それらはすべて次のエラーを生成しました:
-[UICollectionViewData indexPathForItemAtGlobalIndex:]、/ SourceCache/UIKit_Sim/UIKit-2372/UICollectionViewData.m:442でのアサーションエラー
したがって、「reloadData」メソッドを試してください。
ヘッダー/フッターを含むセクションから最後のセルを削除すると、バグが表示されます。
その時に私はヘッダー/フッターのサイズ/要素のnilを返そうとしました、そしてこれは時々問題を修正します。
オプション:
このエラーにつながる可能性のあるチーズボールの間違いは、同じビューコントローラの複数のcollectionViewで同じUICollectionViewFlowLayoutを再利用することです!コレクションビューごとに異なるflowLayoutsを初期化するだけで、準備完了です。
コレクションビューからセルの1つを削除すると、この問題が発生しました。
問題は、カスタムレイアウトを使用していて、layoutAttributesForElementsInRect
を呼び出すと、削除後にコレクションビューのセル数より多くのセルが返されていたことです。
どうやらUICollectionViewは、セルの数をチェックせずに、メソッドによって返された配列を反復処理するだけです。
同じ数のレイアウト属性を返すようにメソッドを変更すると、クラッシュが解決しました。