Crash when reloading collectionView frequently

In an iOs app I am using a collection view that will refresh frequently when the user clicks on a cell in another collection that is on the screen. The collection view gets the data one row at a time and reloads the collection.

Here is the code in the selection:

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
    if (collectionView == self.datePickerCollectionView) {


        [[self.PickerCollectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:self.crtDelta inSection:0]] setSelected:NO];

        if (self.crtDelta == indexPath.item) {
            // in case the user taps on the day he allready is on
            // don't do anything
            return;
        }

        self.crtDelta = indexPath.item;

            [self.attriburesRectDict removeAllObjects];
            [self.CollectionView.collectionViewLayout invalidateLayout];
            [self.CollectionView reloadData];
            [self.TableView reloadData];
            self.DataDict = [NSMutableDictionary new];
      }

// get data from web manager here
}

      

As you can see, the data dictionaries are reset.

- (void)didReceiveDataForSection:(NSInteger)section withDataArray:(NSArray*)data andRectsArray:(NSArray*)rects
{
   self.programsDict[@(index)] = data;
    self.attriburesRectDict[@(index)] = rects;
   [self.programsCollectionView reloadData];
}

      

Here 1 line of data is retrieved and added to the appropriate dictionaries for use. This is the layout code:

@interface MultipleLineLayout()

@property (nonatomic, assign) NSInteger numRows;

@end


@implementation MultipleLineLayout {
    CGFloat itemHeight;
}

-(id)init {
    if (self = [super init]) {
        self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        itemHeight = 0.0;
    }
    return self;
}

-(CGSize)collectionViewContentSize {
    NSInteger xSize = self.contentSizeWidth;
    NSInteger ySize = [self.collectionView numberOfSections] * (itemHeight + PROGRAMS_CELL_SPACING);
    return CGSizeMake(xSize, ySize);
}

-(void)prepareLayout
{
    [super prepareLayout];
    [self.collectionView setBounces:NO];
    if (self.collectionView) {
        self.numRows = [self.collectionView numberOfSections];
    }
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path {
    UICollectionViewLayoutAttributes *a = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path];
    a.frame = [self.dataSource rectForAttributesForRow:path.row inSection:path.section];
    return a;
}

-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSMutableArray* attributes = [NSMutableArray array];
    if (itemHeight == 0.0) {
        itemHeight = [self.dataSource heightOfProgramCell];
    }

    NSUInteger startRow = floorf(rect.origin.y / itemHeight);
    NSUInteger endRow =   ceilf(CGRectGetMaxY(rect) / (CGFloat)itemHeight);
    if (endRow >= self.numRows) {
        endRow = self.numRows ;
    }
    for (NSUInteger r = startRow; r < endRow; r++)
    {
        NSUInteger noProgs = [self.dataSource numberOfElementsInSection:r];
        for (NSUInteger c = 0; c <noProgs; c++)
        {
            UICollectionViewLayoutAttributes* o = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:c inSection:r]];

            if(o.size.width > 0) {
                [attributes addObject:o];
            }
            else {
                break;
            }
        }
    }

    return attributes;
}

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
    return NO;
}

@end

      

The problem is that sometimes if you switch data very often (short for the collection view code shown in the 1st code snippet) (for example, 2 branches per second), the application crashes:

*** Assertion failure in -[UICollectionViewData validateLayoutInRect:], /SourceCache/UIKit/UIKit-2903.23/UICollectionViewData.m:341
2014-08-21 12:14:33.052 du View[365:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView recieved layout attributes for a cell with an index path that does not exist: <NSIndexPath: 0x18c1be10> {length = 2, path = 0 - 0}'
*** First throw call stack:
(0x2dd4cf4b 0x385c36af 0x2dd4ce25 0x2e6f4fe3 0x3051c953 0x3051c063 0x3051b8c7 0x304bfda3 0x30146c6b 0x3014247b 0x3014230d 0x30141d1f 0x30141b2f 0x3013b85d 0x2dd181cd 0x2dd15b71 0x2dd15eb3 0x2dc80c27 0x2dc80a0b 0x32981283 0x30524049 0x14c529 0x38acbab7)
libc++abi.dylib: terminating with uncaught exception of type NSException

      

I believe that this is some kind of hindrance between recharges in didSelectCell and reloads in the received data. I cancel all data requests when switching, but after a while it seems that the collection view enters this confusing state and crashes.

How can I prevent this crash?

+3


source to share


2 answers


I think I figured it out. The problem was numberOfCellsInSection. There I was returning 0 if there was no data, but apparently this method is not called often enough, so when the data was available, it still expected 0. Changed this to return 100 and never saw a failure again.



+3


source


It would be more efficient and efficient to work with insertItemsAtIndexPaths:

instead of reloading the entire view when only one view is added at a time, and also prevents weird scrolling artifacts from appearing.



0


source







All Articles