web-dev-qa-db-ja.com

iOS7のUICollectionViewData validateLayoutInRectでのアサーションエラー

IOS7でのUICollectionViewDatavalidateLayoutInRectでのアサーションエラー。

UICollectionViewループを使用して、すべてのforアイテムを1つずつ削除しようとしています。以下のコードを投稿しました。 UICollectionViewを使用してdeleteItemsAtIndexPathsアイテムを削除します。これはiOS6で完全に機能するですが、iOS7ではクラッシュですが、次の例外があります。

UICollectionViewData validateLayoutInRectでのアサーションエラー

collectionArrayからオブジェクトを削除し、次にindexPathを使用してself.collectionViewを1つずつ削除します。 4番目のオブジェクトを削除すると、iOS7でAssertion failureが発生します。ここではperformBatchUpdatesを使用しています。

IOS7で適切な結果を得るのを手伝ってください。適切なコードを共有します。前もって感謝します。

try  {    
    for (int i=count-1; i>=0; i--)  {  
        [self.collectionView performBatchUpdates:^(void){  
            [collectionArray removeObjectAtIndex:i]; // First delete the item from you model   
            [self.collectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]]];  
        } completion:nil];
        [self.collectionView reloadData];
    }
}
@catch (NSException *exception) {
}
@finally {
}
20
user1888996

実際にこのクラッシュが発生したのは、セクションまたはセクション内のアイテムの数に対してゼロを返したからではなく、次のようなフローレイアウトを複数のコレクションビューで再利用したためです。

UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
Collection1 = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 50.0f) collectionViewLayout:flowLayout];
[Collection1 setDataSource:self];
[Collection1 setDelegate:self];
[self.view addSubview:Collection1];

Collection2 = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, self.view.frame.size.height) collectionViewLayout:flowLayout];
Collection2.backgroundColor = [UIColor whiteColor];

代わりに、UICollectionViewごとに新しいフローレイアウトを作成すると、このクラッシュを回避できます。うまくいけば、それは誰かを助けるかもしれません

UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
Collection1 = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 50.0f) collectionViewLayout:flowLayout];
[Collection1 setDataSource:self];
[Collection1 setDelegate:self];
[self.view Collection1];

UICollectionViewFlowLayout *flowLayoutVert = [[UICollectionViewFlowLayout alloc] init];
[flowLayoutVert setScrollDirection:UICollectionViewScrollDirectionVertical];
Collection2 = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, self.view.frame.size.height) collectionViewLayout:flowLayoutVert];
24
ColossalChris

iOS 10では、prefetchingEnabledを無効にする必要があります。

// Swift
if #available(iOS 10, *) { 
    collectionView.prefetchingEnabled = false 
}

//Obj C
if ([self.collectionView respondsToSelector:@selector(setPrefetchingEnabled:)]) {
    self.collectionView.prefetchingEnabled = false;
}
20
dang

おそらくこれを実行したいようです:

[self.CollectionView performBatchUpdates:^(void) {
  for (int i = count - 1; i >= 0; i--) {
    [collectionArray removeObjectAtIndex:i]; // First delete the item from you model
    [self.CollectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]]];
  }
} completion:nil];

すべての更新が一緒に実行されるようにします。そうしないと、複数のバッチ更新を重ねて実行しようとすることになります。

3
James Snook

layout lifecycle

layoutClassinvalidateLayoutを実装し、構成内のすべての種類のUICollectionViewLayoutAttributes項目を削除する必要があります。

- (void)invalidateLayout{
  [super invalidateLayout];
  [self.itemsAttributes removeAllObjects];
}
3
Zev003

[yourCollectionView.collectionViewLayout invalidateLayout];を呼び出してみてください

2
Aks

レイアウトクラスにinvalidateLayoutを実装し、すべての種類のUICollectionViewLayoutAttributes項目を構成から削除する必要があります。

- (void)invalidateLayout{
  [super invalidateLayout];
  [self.itemsAttributes removeAllObjects];
}

invalidateLayoutWithContextを実装するより良い方法については、UICollectionViewLayoutInvalidationContextの詳細をご覧ください。

Apple Developerのドキュメント から:

カスタムレイアウトを実装する場合、このメソッドをオーバーライドして、カスタム無効化コンテキストによって提供される情報を処理するために使用できます。カスタム無効化コンテキストを提供する必要はありませんが、レイアウトの更新を最適化するのに役立つ追加のプロパティを提供できる場合は、そうする可能性があります。このメソッドをオーバーライドする場合は、実装のある時点でsuperを呼び出す必要があります。

1
Zev003

私の場合、次のデリゲートがありませんでした:

func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
0