生成新单元格时清除集合视图单元格(iOS7-AFNetworking)
我有一个集合视图控制器,其中的单元格通过JSON调用获取内容。每个单元格都有一个滚动视图(图像幻灯片)。我注意到幻灯片是在旧的幻灯片上加载的(我可以看到旧单元格中的幻灯片在加载新幻灯片之前出现)。或者,如果我滑动第一个单元格的第三个图像,然后滚动第四个单元格,它会显示第三个图像(而不是第一个),但页面控件会显示这是第一张幻灯片 在生成新单元格时,如何“清除”旧单元格(或至少清除滚动视图,或阻止其被重用) 第h条(对象) Article.m(NSObject) 集合视图控制器生成新单元格时清除集合视图单元格(iOS7-AFNetworking),ios,json,uiscrollview,afnetworking,uicollectionviewcell,Ios,Json,Uiscrollview,Afnetworking,Uicollectionviewcell,我有一个集合视图控制器,其中的单元格通过JSON调用获取内容。每个单元格都有一个滚动视图(图像幻灯片)。我注意到幻灯片是在旧的幻灯片上加载的(我可以看到旧单元格中的幻灯片在加载新幻灯片之前出现)。或者,如果我滑动第一个单元格的第三个图像,然后滚动第四个单元格,它会显示第三个图像(而不是第一个),但页面控件会显示这是第一张幻灯片 在生成新单元格时,如何“清除”旧单元格(或至少清除滚动视图,或阻止其被重用) 第h条(对象) Article.m(NSObject) 集合视图控制器 - (void)se
- (void)setLatestNews:(NSArray *)latestNews {
_latestNews = latestNews;
[self.collectionView reloadData];
}
- (void)loadData:(id)sender {
[Article latestNewsWithBlock:^(NSArray *news, NSError *error) {
self.latestNews = news;
}];
}
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.collectionView registerClass:[ArticleCell class] forCellWithReuseIdentifier:@"ArticleCell"];
[self loadData:nil];
}
#pragma mark - UICollectionViewDataSource
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = @"articleCell";
ArticleCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
cell.article = [self.latestNews objectAtIndex:indexPath.row];
return cell;
}
集合视图单元格
@interface ArticleCell ()
@property (readwrite, nonatomic, strong) NSArray *pageImages;
@end
@implementation ArticleCell
- (void)setArticle:(Article *)article {
_article = article;
self.pageImages = [self.article.images valueForKeyPath:@"URL"];
NSUInteger pageCount = [self.pageImages count];
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = pageCount;
self.pageControl.hidden = (pageCount == 1);
for (NSInteger page = 0; page < pageCount; page++) {
CGRect frame = self.scrollView.bounds;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0.0f;
UIImageView *imageView = [[UIImageView alloc] init];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.frame = frame;
[imageView setImageWithURL:self.pageImages[page]];
[self.scrollView addSubview:imageView];
}
CGSize pagesScrollViewSize = self.scrollView.frame.size;
self.scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width * self.pageImages.count, pagesScrollViewSize.height);
}
@接口ArticleCell()
@属性(读写、非原子、强)NSArray*pageImages;
@结束
@实现单元
-(无效)设定条款:(第*)条{
_第条=第条;
self.pageImages=[self.article.images值forkeypath:@“URL”];
nsuiger pageCount=[self.pageImages count];
self.pageControl.currentPage=0;
self.pageControl.numberOfPages=页面计数;
self.pageControl.hidden=(pageCount==1);
对于(NSInteger page=0;page
谢谢。您之所以看到这一点,是因为这些单元正在被重用(这对于性能来说是一件好事) 如果在重新使用单元格时需要从单元格中删除旧内容,则需要在collectionView:cellForItemAtIndexPath:中将其删除 在您的情况下,在添加新的ImageView之前,需要对添加到scrollView的所有ImageView调用removeFromSuperview
您还可以在UICollectionViewCell方法prepareForReuse中进行一些重用准备。但是,出于UITableViewCells性能方面的原因,Apple建议“只重置与内容无关的单元格属性,例如alpha、编辑和选择状态。”。假设同样的建议也适用于UICollectionViewCells。示例项目可在此处找到: 在ArticleCell中将其作为公共方法实现:
- (void)cleanForReuse
{
[[self.scrollView subviews]
makeObjectsPerformSelector:@selector(removeFromSuperview)];
self.scrollView.contentSize = CGSizeZero;
}
- (void)prepareForReuse
{
[super prepareForReuse];
self.pageImages = nil;
}
然后在重用单元格之前更新代码以调用cleanForReuse:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = @"articleCell";
ArticleCell *cell =
[collectionView dequeueReusableCellWithReuseIdentifier:identifier
forIndexPath:indexPath];
[cell cleanForReuse];
cell.article = [self.latestNews objectAtIndex:indexPath.row];
return cell;
}
对添加到scrollView的每个图像视图调用removeFromSuperview。您可能需要一个数组属性来存储它们,以使它们更易于访问。不要以这种方式使用
prepareforeuse
。出于性能原因,您应该只重置与内容无关的单元格属性。例如,alpha、编辑和选择状态。有趣的是,我以前从未听说过这一点。我真的不明白为什么在PrepareForuse中做某件事比在collectionView:cellForItemAtIndexPath中做要耗费大量资源。无论哪种方式,您都需要在重新使用单元之前重置单元的状态。你知道关于这个话题有什么好的评论吗?我在搜索中找不到任何相关内容。苹果在UITableViewCell
的文档中指出了这一点。应该注意的是,它们对UICollectionReusableView
没有相同的注释,但它们确实指出“子类可以重写此方法以将任何新数据分配给视图”,这似乎表明了类似的方法(没有UI更改)。删除和重新创建子视图会破坏单元重用的大部分要点。例如,我将UIImageView的图像
设置为nil
,但下次单元格出现时重新使用UIImageView。如果我在生成新的滚动视图后向上滚动,此代码将擦除我的滚动视图。@Chris您还有其他事情要做。这段代码正在我的测试项目中工作。我用我拥有的NSObject(“Article”)更新了我的代码,它会解析我的JSON字符串,以防产生影响。删除和重新创建子视图会破坏单元重用的大部分要点。@AaronBrager你错了。重用的要点是,如果您必须不断地反复重新初始化单元格对象,则可以最大限度地减少内存波动,并提高滚动性能,否则,由于为每一行创建新单元格对象的延迟,滚动性能会出现问题。重用与单元格的内容无关。事实上,如果您从未删除scrollView的子视图,则每行的子视图数量将增加一倍。顺便说一句,您通常不希望创建像您的文章属性那样具有副作用的属性。相反,删除setArticle
并创建一个调用的-(void)configureForArticle:(Article*)Article
方法,然后该方法可以执行所有必要的代码并设置Article
属性。
- (void)cleanForReuse
{
[[self.scrollView subviews]
makeObjectsPerformSelector:@selector(removeFromSuperview)];
self.scrollView.contentSize = CGSizeZero;
}
- (void)prepareForReuse
{
[super prepareForReuse];
self.pageImages = nil;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = @"articleCell";
ArticleCell *cell =
[collectionView dequeueReusableCellWithReuseIdentifier:identifier
forIndexPath:indexPath];
[cell cleanForReuse];
cell.article = [self.latestNews objectAtIndex:indexPath.row];
return cell;
}