UICollectionView performance issues on performBatchUpdates

We are trying to customize a UICollectionView using a custom layout. The contents of each CollectionViewCell will be an image. For all this there will be several thousand images and about 140-150 visible at a certain time. In the event of an action, potentially all cells will be reorganized into position and size. The goal is to animate all moving events currently using the performBatchUpdates method. This leads to a huge delay time before everything becomes animated.

So far, we have found that internally the layoutAttributesForItemAtIndexPath method is called for each individual cell (only a few thousand). In addition, the cellForItemAtIndexPath method is called for more cells than can actually be displayed on the screen.

Are there any ways to improve animation performance?


By default, UICollectionViewFlowLayout cannot really offer the design that we want to implement in the application. Here are some of our code:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { RPDataModel *dm = [RPDataModel sharedInstance]; //Singleton holding some global information NSArray *plistArray = dm.plistArray; //Array containing the contents of the cells NSDictionary *dic = plistArray[[indexPath item]]; RPCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CELL" forIndexPath:indexPath]; cell.label.text = [NSString stringWithFormat:@"%@",dic[@"name"]]; cell.layer.borderColor = nil; cell.layer.borderWidth = 0.0f; [cell loadAndSetImageInBackgroundWithLocalFilePath:dic[@"path"]]; //custom method realizing asynchronous loading of the image inside of each cell return cell; } 

LayoutAttributesForElementsInRect iterates through all the elements, setting the layoutAttributes for all the elements in the rectangle. The delay for the operator is divided into the first cell beyond the boundaries defined by the lower right corner of the rectangle:

 -(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect { NSMutableArray* attributes = [NSMutableArray array]; RPDataModel *dm = [RPDataModel sharedInstance]; for (int i = 0; i < dm.cellCount; i++) { CGRect cellRect = [self.rp getCell:i]; //self.rp = custom object offering methods to get information about cells; the getCell method returns the rect of a single cell if (CGRectIntersectsRect(rect, cellRect)) { NSIndexPath *indexPath = [NSIndexPath indexPathForItem:[dm.relevanceArray[i][@"product"] intValue] inSection:0]; UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; attribute.size = cellRect.size; attribute.center = CGPointMake(cellRect.origin.x + attribute.size.width / 2, cellRect.origin.y + attribute.size.height / 2); [attributes addObject:attribute]; } else if (cellRect.origin.x > rect.origin.x + rect.size.width && cellRect.origin.y > rect.origin.y + rect.size.height) { break; } } return attributes; } 

If you change the layout, the results are almost the same regardless of whether the number of cells defined in layoutAttributesForElementsInRect is limited or not. Either the system receives layout attributes for all cells, if they are not limited, or it calls the layoutAttributesForElementAtIndexPath method for all missing cells, if it is limited. In general, the attributes for each individual cell are used somehow.

 -(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { RPDataModel *dm = [RPDataModel sharedInstance]; UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; CGRect cellRect = [self.rp getCell:[dm.indexDictionary[@(indexPath.item)] intValue]]; attribute.size = cellRect.size; attribute.center = CGPointMake(cellRect.origin.x + attribute.size.width / 2, cellRect.origin.y + attribute.size.height / 2); return attribute; } 
+6
source share
2 answers

Without seeing the code, I assume that your layoutAttributesForElementsInRect method iterates over all the elements of your collection, and this, in turn, leads to other methods being redirected. layoutAttributesForElementsInRect gives you a hint - that is, the CGRect that it passes to you - about what elements you need to call layoutAttributesForItemAtIndexPath for, in terms of what is on the screen.

Thus, this may be part of a performance problem, i.e. Customize your layout so that it’s smart about which items it updates.

Other issues relate to overall animation performance. The only thing you need to pay attention to is if there are any compositions, make sure that your images are opaque. Another thing, if you use shadows on your image, they can be expensive for animation. One way to improve the performance of shadow animation is to set the shadowPath value when resizing the image - if you have shadows, let me know and post the code for this.

+3
source

This seems to be due to an attempt to add cells to sections that have headers but no longer have cells.

The error message is monumentally useless, and it took several hours of effort to trace it.

0
source

Source: https://habr.com/ru/post/926101/


All Articles