频繁重新加载collectionView时崩溃
Posted
技术标签:
【中文标题】频繁重新加载collectionView时崩溃【英文标题】:Crash when reloading collectionView frequently 【发布时间】:2014-08-21 09:18:18 【问题描述】:在一个 ios 应用程序中,我使用了一个集合视图,当用户点击屏幕上不同集合视图中的单元格时,该集合视图将经常更新。集合视图一次接收一行数据并重新加载集合视图。
这里是选择中的代码:
- (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
如您所见,数据字典已重置。
- (void)didReceiveDataForSection:(NSInteger)section withDataArray:(NSArray*)data andRectsArray:(NSArray*)rects
self.programsDict[@(index)] = data;
self.attriburesRectDict[@(index)] = rects;
[self.programsCollectionView reloadData];
这里接收到1行数据,添加到相关字典中使用。 这是布局代码:
@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
问题在于,有时如果您非常频繁地切换数据(点击第一个代码 sn-p 中显示的集合视图代码)(例如每秒点击 2 次),应用程序会崩溃:
*** 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
我相信这是 didSelectCell 中的重新加载和 did 接收数据中的重新加载之间的某种干扰。我确实在切换时取消了所有数据请求,但不知何故,一段时间后,集合视图似乎进入了这种混乱状态并崩溃。
如何防止这种崩溃?
【问题讨论】:
【参考方案1】:我想我明白了。问题出在 numberOfCellsInSection 中。如果没有数据可用,我会返回 0,但显然该方法调用的频率不够高,因此当数据可用时,它仍然期望 0。将其更改为返回 100,并且不再看到崩溃。
【讨论】:
【参考方案2】:当一次只添加一个视图时,insertItemsAtIndexPaths:
比重新加载整个视图更高效和高效,而且它还可以防止奇怪的滚动伪影。
【讨论】:
我同意!或者,也许做一堆处理,然后重新加载整个事情一次。不知道是谁给你的大拇指向下,但我反驳了这一点。特别是因为我真的不喜欢他的“解决方案”。 :-)以上是关于频繁重新加载collectionView时崩溃的主要内容,如果未能解决你的问题,请参考以下文章
屏幕重新加载时 CollectionView 单元格更改大小
CollectionView 标题在滚动时停止刷新/重新加载数据
如何在不重新加载图像的情况下重新加载 collectionview 单元格