UICollectionView断言失败(UICollectionView Assertion fa

2019-06-18 08:36发布

我米上执行收到此错误insertItemsAtIndexPathsUICollectionView

断言失败:

-[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'

我已经检查过我的数据源仅包含一个元素。 为什么这可能发生的任何见解? 如果需要更多信息,我可以肯定地提供。

Answer 1:

将第一单元到一个集合视图时,我就遇到了这个同样的问题。 我改变我的代码解决了这个问题,让我叫UICollectionView

- (void)reloadData

方法时将所述第一小区,但

- (void)insertItemsAtIndexPaths:(NSArray *)indexPaths

将所有其他单元格时。

有趣的是,我也有一个问题

- (void)deleteItemsAtIndexPaths:(NSArray *)indexPaths

删除最后一个单元格时。 我做同样的事情之前,只要调用reloadData删除最后一个单元格时。



Answer 2:

插入分节#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];


Answer 3:

我已经发布了针对此问题的工作在这里: 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];
    }
}

信用这种方法去布莱克·沃特斯。



Answer 4:

这是一种非劈,基于文档,这个问题的答案。 就我而言,有根据,我会返回一个有效的或从零补充视图条件collectionView:viewForSupplementaryElementOfKind:atIndexPath: 遭遇车祸后,我查了文档,这里是他们在说什么:

此方法必须始终返回一个有效的视图对象。 如果你不希望在特定情况下的补充视图,布局对象不应创建该视图的属性。 或者,也可以通过设置相应的属性为YES的隐藏属性隐藏视图或属性的alpha属性设置为0。要隐藏在流布局页眉和页脚的观点,还可以设置的那些视图的宽度和高度为0。

还有其他的方法可以做到这一点,但最快的似乎是:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
    return <condition> ? collectionViewLayout.headerReferenceSize : CGSizeZero;
}


Answer 5:

我的收藏视图是从两个数据源获取项目,并更新他们造成的这一问题。 我的解决方法是队列中的数据更新和集合视图重装在一起:

[[NSOperationQueue mainQueue] addOperationWithBlock:^{

                //Update Data Array
                weakSelf.dataProfile = [results lastObject]; 

                //Reload CollectionView
                [weakSelf.collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:0 inSection:0]]];
 }];


Answer 6:

检查你正在重返正确的元素数量UICollectionViewDataSource方法:

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView


Answer 7:

我就遇到了这个问题为好。 这里就是发生在我身上:

  1. 我子类UICollectionViewController和上initWithCollectionViewLayout:被初始化我NSFetchedResultsController
  2. 有一个共同的类取从NSURLConnection的结果和解析JSON串(不同的线程)
  3. 通过原料管路,创造我的NSManagedObjects ,将它们添加到我NSManagedObjectContext ,其中有主线程的NSManagedObjectContext作为parentContext
  4. 保存我的背景。
  5. 有我NSFetchedResultsController拿起变化并预约。
  6. - (void)controllerDidChangeContent:我会处理的变化,并将其应用到我的UICollectionView

间歇性的,我会得到OP越来越错误,无法找出原因。

要解决这个问题,让我感动的NSFetchedResultsController初始化和performFetch- viewDidLoad的方法。这个问题现在已经没有了。 无需调用[collectionView reloadData]或任何东西,所有的动画工作正常。

希望这可以帮助!



Answer 8:

看来,当你插入或小区移动到包含补充页眉或页脚视图(用部分出现问题UICollectionViewFlowLayout或从衍生的布局),并且部分具有前插入/移动0细胞的计数。

我只能规避碰撞并仍然由具有在包含这样的补充头部视图部分的空的和不可见的细胞保持动画:

  1. 使- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section返回实际细胞计数`+ 1该节其中报头视图。
  2. - (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"]; 
  3. 使用moveItemAtIndexPath:insertItemsAtIndexPaths:没有崩溃。


Answer 9:

下面是我想我会在这里发布的情况下,任何发现有价值的这个错误我已经用我的项目的解决方案。

@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];
}


Answer 10:

在我的情况下,问题是我是我创造的方式NSIndexPath 。 例如,要删除第三单元,而不是做:

NSIndexPath* indexPath = [NSIndexPath indexPathWithIndex:2];
[_collectionView deleteItemsAtIndexPaths:@[indexPath]];

我需要做的:

NSIndexPath* indexPath = [NSIndexPath indexPathForItem:2 inSection:0];
[_collectionView deleteItemsAtIndexPaths:@[indexPath]];


Answer 11:

检查您在返回正确的值numberOfSectionsInCollectionView:

我用计算部分中的值为零,从而0部分。 这引起了异常。

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    NSInteger sectionCount = self.objectThatShouldHaveAValueButIsActuallyNil.sectionCount;

    // section count is wrong!

    return sectionCount;
}


Answer 12:

只是为了记录在案,我遇到了同样的问题,我的解决方法是删除页眉(在的.xib禁用它们)和没有需要他们删除了这个方法。 在那之后一切似乎罚款。

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementary
ElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath


Answer 13:

我打这个问题我自己。 这里所有的答案似乎存在的问题,除了亚历克斯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]]];
    }];
}


Answer 14:

实际工作的解决方法是返回的高度为0,如果你补充视图的索引路径的电池是不存在的(初始负荷,你已经删除的行等)。 看到这里我的答案:

https://stackoverflow.com/a/18411860/917104



文章来源: UICollectionView Assertion failure