UICollectionView 어설 션 실패
수행 할 때이 오류가 발생합니다 insertItemsAtIndexPaths
.UICollectionView
다음에서 어설 션 실패 :
-[UICollectionViewData indexPathForItemAtGlobalIndex:],
/SourceCache/UIKit/UIKit-2372/UICollectionViewData.m:442
2012-09-26 18:12:34.432
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: 'request for index path for global index 805306367
when there are only 1 items in the collection view'
확인했고 데이터 소스에 요소가 하나만 포함되어 있습니다. 왜 이런 일이 일어날 수 있는지에 대한 통찰력이 있습니까? 더 많은 정보가 필요하면 확실히 제공 할 수 있습니다.
컬렉션 뷰에 첫 번째 셀을 삽입 할 때 이와 동일한 문제가 발생했습니다. UICollectionView를 호출하도록 코드를 변경하여 문제를 해결했습니다.
- (void)reloadData
첫 번째 셀을 삽입 할 때 메서드를 사용하지만
- (void)insertItemsAtIndexPaths:(NSArray *)indexPaths
다른 모든 셀을 삽입 할 때.
흥미롭게도, 나는 또한 문제가 있었다 과를
- (void)deleteItemsAtIndexPaths:(NSArray *)indexPaths
마지막 셀을 삭제할 때. 전과 똑같은 일을했습니다 reloadData
. 마지막 셀을 삭제할 때 전화 만하면 됩니다.
셀을 삽입하기 직전에 섹션 # 0을 삽입하면 UICollectionView가 행복해 보입니다.
NSArray *indexPaths = /* indexPaths of the cells to be inserted */
NSUInteger countBeforeInsert = _cells.count;
dispatch_block_t updates = ^{
if (countBeforeInsert < 1) {
[self.collectionView insertSections:[NSIndexSet indexSetWithIndex:0]];
}
[self.collectionView insertItemsAtIndexPaths:indexPaths];
};
[self.collectionView performBatchUpdates:updates completion:nil];
이 문제에 대한 해결 방법을 여기에 게시했습니다 : https://gist.github.com/iwasrobbed/5528897
.m
파일 상단의 비공개 카테고리에서 :
@interface MyViewController ()
{
BOOL shouldReloadCollectionView;
NSBlockOperation *blockOperation;
}
@end
그러면 대리인 콜백은 다음과 같습니다.
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
shouldReloadCollectionView = NO;
blockOperation = [NSBlockOperation new];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
__weak UICollectionView *collectionView = self.collectionView;
switch (type) {
case NSFetchedResultsChangeInsert: {
[blockOperation addExecutionBlock:^{
[collectionView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]];
}];
break;
}
case NSFetchedResultsChangeDelete: {
[blockOperation addExecutionBlock:^{
[collectionView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]];
}];
break;
}
case NSFetchedResultsChangeUpdate: {
[blockOperation addExecutionBlock:^{
[collectionView reloadSections:[NSIndexSet indexSetWithIndex:sectionIndex]];
}];
break;
}
default:
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
__weak UICollectionView *collectionView = self.collectionView;
switch (type) {
case NSFetchedResultsChangeInsert: {
if ([self.collectionView numberOfSections] > 0) {
if ([self.collectionView numberOfItemsInSection:indexPath.section] == 0) {
shouldReloadCollectionView = YES;
} else {
[blockOperation addExecutionBlock:^{
[collectionView insertItemsAtIndexPaths:@[newIndexPath]];
}];
}
} else {
shouldReloadCollectionView = YES;
}
break;
}
case NSFetchedResultsChangeDelete: {
if ([self.collectionView numberOfItemsInSection:indexPath.section] == 1) {
shouldReloadCollectionView = YES;
} else {
[blockOperation addExecutionBlock:^{
[collectionView deleteItemsAtIndexPaths:@[indexPath]];
}];
}
break;
}
case NSFetchedResultsChangeUpdate: {
[blockOperation addExecutionBlock:^{
[collectionView reloadItemsAtIndexPaths:@[indexPath]];
}];
break;
}
case NSFetchedResultsChangeMove: {
[blockOperation addExecutionBlock:^{
[collectionView moveItemAtIndexPath:indexPath toIndexPath:newIndexPath];
}];
break;
}
default:
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
// Checks if we should reload the collection view to fix a bug @ http://openradar.appspot.com/12954582
if (shouldReloadCollectionView) {
[self.collectionView reloadData];
} else {
[self.collectionView performBatchUpdates:^{
[blockOperation start];
} completion:nil];
}
}
이 접근 방식에 대한 크레딧은 Blake Watters에게 있습니다.
다음은 문제에 대한 해킹이 아닌 문서 기반 답변입니다. 제 경우에는에서 유효한 또는 nil 보충보기를 반환하는 조건이있었습니다 collectionView:viewForSupplementaryElementOfKind:atIndexPath:
. 충돌이 발생한 후 문서를 확인했으며 다음과 같이 말합니다.
이 메서드는 항상 유효한 뷰 개체를 반환해야합니다. 특정 경우에 추가보기를 원하지 않는 경우 레이아웃 개체는 해당보기에 대한 속성을 생성하지 않아야합니다. 또는 해당 속성의 숨김 속성을 YES로 설정하거나 속성의 alpha 속성을 0으로 설정하여보기를 숨길 수 있습니다. 흐름 레이아웃에서 머리글 및 바닥 글보기를 숨기려면 해당보기의 너비와 높이를 설정할 수도 있습니다. 0으로.
이를 수행하는 다른 방법이 있지만 가장 빠른 방법은 다음과 같습니다.
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
return <condition> ? collectionViewLayout.headerReferenceSize : CGSizeZero;
}
내 컬렉션 뷰가 두 개의 데이터 소스에서 항목을 가져 와서 업데이트하면이 문제가 발생했습니다. 내 해결 방법은 데이터 업데이트와 컬렉션 뷰를 함께 다시로드하는 것입니다.
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//Update Data Array
weakSelf.dataProfile = [results lastObject];
//Reload CollectionView
[weakSelf.collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:0 inSection:0]]];
}];
UICollectionViewDataSource
메소드 에서 올바른 수의 요소를 리턴하는지 확인하십시오 .
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
과
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
이 문제도 발생했습니다. 나에게 일어난 일은 다음과 같습니다.
- 나는 UICollectionViewController를 서브 클래스와,에
initWithCollectionViewLayout:
, 내 초기화되었다NSFetchedResultsController
. - 공유 클래스가 NSURLConnection에서 결과를 가져오고 JSON 문자열 (다른 스레드)을 구문 분석하도록합니다.
- 루프 피드를 통해 내를 만들
NSManagedObjects
내에 추가,NSManagedObjectContext
이 메인 스레드의있는NSManagedObjectContext
A와parentContext
. - 내 맥락을 저장하십시오.
- 내 한
NSFetchedResultsController
변경 사항을 선택하고 그들을 대기. - 에
- (void)controllerDidChangeContent:
, 나는 변경 사항을 처리하는 것하고 내 적용됩니다UICollectionView
.
간헐적으로 OP에 오류가 발생하고 그 이유를 알 수 없습니다.
이 문제를 해결하기 위해 NSFetchedResultsController
초기화와 방법 performFetch
을 이동 - viewDidLoad
했는데이 문제는 이제 사라졌습니다. 전화를 걸 [collectionView reloadData]
거나 아무것도 할 필요가 없으며 모든 애니메이션이 제대로 작동합니다.
도움이 되었기를 바랍니다!
보조 머리글 또는 바닥 글보기 ( UICollectionViewFlowLayout
그로부터 파생 된 레이아웃 포함)가 포함 된 섹션에 셀을 삽입하거나 이동할 때 문제가 발생 하고 삽입 / 이동하기 전에 섹션에 0 개의 셀이있는 것 같습니다.
다음과 같이 보조 헤더 뷰를 포함하는 섹션에 비어 있고 보이지 않는 셀을 두어 충돌을 피하고 애니메이션을 계속 유지할 수 있습니다.
- 확인
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section
헤더보기가 그 부분에 대한 실제 세포`카운트 + 1을 반환합니다. 에
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
반환if ((indexPath.section == YOUR_SECTION_WITH_THE_HEADER_VIEW) && (indexPath.item == [self collectionView:collectionView numberOfItemsInSection:indexPath.section] - 1)) { cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"EmptyCell" forIndexPath:indexPath]; }
... 그 위치에 대한 빈 셀.
viewDidLoad
UICollectionView를 초기화 할 때마다 셀 재사용을 등록해야합니다 .[self.collectionView registerClass:[UICollectionReusableView class] forCellWithReuseIdentifier:@"EmptyCell"];
- 충돌없이 사용
moveItemAtIndexPath:
하거나 사용합니다insertItemsAtIndexPaths:
.
여기에 내가 프로젝트에서 사용하고있는이 버그에 대한 해결책이 있습니다.
@interface FetchedResultsViewController ()
@property (nonatomic) NSMutableIndexSet *sectionsToAdd;
@property (nonatomic) NSMutableIndexSet *sectionsToDelete;
@property (nonatomic) NSMutableArray *indexPathsToAdd;
@property (nonatomic) NSMutableArray *indexPathsToDelete;
@property (nonatomic) NSMutableArray *indexPathsToUpdate;
@end
#pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self resetFetchedResultControllerChanges];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
switch(type)
{
case NSFetchedResultsChangeInsert:
[self.sectionsToAdd addIndex:sectionIndex];
break;
case NSFetchedResultsChangeDelete:
[self.sectionsToDelete addIndex:sectionIndex];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
switch(type)
{
case NSFetchedResultsChangeInsert:
[self.indexPathsToAdd addObject:newIndexPath];
break;
case NSFetchedResultsChangeDelete:
[self.indexPathsToDelete addObject:indexPath];
break;
case NSFetchedResultsChangeUpdate:
[self.indexPathsToUpdate addObject:indexPath];
break;
case NSFetchedResultsChangeMove:
[self.indexPathsToAdd addObject:newIndexPath];
[self.indexPathsToDelete addObject:indexPath];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
if (self.sectionsToAdd.count > 0 || self.sectionsToDelete.count > 0 || self.indexPathsToAdd.count > 0 || self.indexPathsToDelete > 0 || self.indexPathsToUpdate > 0)
{
if ([self shouldReloadCollectionViewFromChangedContent])
{
[self.collectionView reloadData];
[self resetFetchedResultControllerChanges];
}
else
{
[self.collectionView performBatchUpdates:^{
if (self.sectionsToAdd.count > 0)
{
[self.collectionView insertSections:self.sectionsToAdd];
}
if (self.sectionsToDelete.count > 0)
{
[self.collectionView deleteSections:self.sectionsToDelete];
}
if (self.indexPathsToAdd.count > 0)
{
[self.collectionView insertItemsAtIndexPaths:self.indexPathsToAdd];
}
if (self.indexPathsToDelete.count > 0)
{
[self.collectionView deleteItemsAtIndexPaths:self.indexPathsToDelete];
}
for (NSIndexPath *indexPath in self.indexPathsToUpdate)
{
[self configureCell:[self.collectionView cellForItemAtIndexPath:indexPath]
atIndexPath:indexPath];
}
} completion:^(BOOL finished) {
[self resetFetchedResultControllerChanges];
}];
}
}
}
// This is to prevent a bug in UICollectionView from occurring.
// The bug presents itself when inserting the first object or deleting the last object in a collection view.
// http://stackoverflow.com/questions/12611292/uicollectionview-assertion-failure
// This code should be removed once the bug has been fixed, it is tracked in OpenRadar
// http://openradar.appspot.com/12954582
- (BOOL)shouldReloadCollectionViewFromChangedContent
{
NSInteger totalNumberOfIndexPaths = 0;
for (NSInteger i = 0; i < self.collectionView.numberOfSections; i++)
{
totalNumberOfIndexPaths += [self.collectionView numberOfItemsInSection:i];
}
NSInteger numberOfItemsAfterUpdates = totalNumberOfIndexPaths;
numberOfItemsAfterUpdates += self.indexPathsToAdd.count;
numberOfItemsAfterUpdates -= self.indexPathsToDelete.count;
BOOL shouldReload = NO;
if (numberOfItemsAfterUpdates == 0 && totalNumberOfIndexPaths == 1)
{
shouldReload = YES;
}
if (numberOfItemsAfterUpdates == 1 && totalNumberOfIndexPaths == 0)
{
shouldReload = YES;
}
return shouldReload;
}
- (void)resetFetchedResultControllerChanges
{
[self.sectionsToAdd removeAllIndexes];
[self.sectionsToDelete removeAllIndexes];
[self.indexPathsToAdd removeAllObjects];
[self.indexPathsToDelete removeAllObjects];
[self.indexPathsToUpdate removeAllObjects];
}
제 경우 문제는 제가 NSIndexPath
. 예를 들어, 다음을 수행하는 대신 세 번째 셀을 삭제하려면 다음을 수행하십시오.
NSIndexPath* indexPath = [NSIndexPath indexPathWithIndex:2];
[_collectionView deleteItemsAtIndexPaths:@[indexPath]];
해야 할 일 :
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:2 inSection:0];
[_collectionView deleteItemsAtIndexPaths:@[indexPath]];
올바른 값을 반환하고 있는지 확인하십시오. numberOfSectionsInCollectionView:
섹션을 계산하는 데 사용한 값은 nil이므로 0
섹션이 있습니다. 이로 인해 예외가 발생했습니다.
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
NSInteger sectionCount = self.objectThatShouldHaveAValueButIsActuallyNil.sectionCount;
// section count is wrong!
return sectionCount;
}
기록을 위해 동일한 문제가 발생했으며 해결책은 헤더를 제거하는 것이었고 (.xib에서 비활성화) 더 이상 필요하지 않았기 때문에이 방법을 제거했습니다. 그 후 모든 것이 잘 보입니다.
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementary
ElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
이 문제를 직접 해결했습니다. 여기에있는 모든 대답은 Alex L을 제외하고는 문제가있는 것처럼 보였습니다. 업데이트를 참조하면 그쪽으로 대답하는 것 같았습니다. 내 최종 해결책은 다음과 같습니다.
- (void)addItem:(id)item {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
if (!_data) {
_data = [NSMutableArray arrayWithObject:item];
} else {
[_data addObject:item];
}
[_collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:_data.count-1 inSection:0]]];
}];
}
The workaround that actually works is to return a height of 0 if the cell at your supplementary view's index path is not there (initial load, you've deleted the row, etc). See my answer here:
https://stackoverflow.com/a/18411860/917104
참고URL : https://stackoverflow.com/questions/12611292/uicollectionview-assertion-failure
'Program Tip' 카테고리의 다른 글
Javascript에서 NaN 값이 같은지 비교 (0) | 2020.12.08 |
---|---|
MurmurHash-무엇입니까? (0) | 2020.12.08 |
INSERT 문을 사용하여 MySQL Workbench로 테이블 내보내기 (0) | 2020.12.08 |
Git : 어떤 커밋이 줄의 범위에 닿았는지 발견 (0) | 2020.12.08 |
UINavigationController를 사용하지 않고 Storyboard에서 UINavigationBar의 높이를 변경하는 방법이 있습니까? (0) | 2020.12.08 |