生成新单元格时清除集合视图单元格(iOS7-AFNetworking)

生成新单元格时清除集合视图单元格(iOS7-AFNetworking),ios,json,uiscrollview,afnetworking,uicollectionviewcell,Ios,Json,Uiscrollview,Afnetworking,Uicollectionviewcell,我有一个集合视图控制器,其中的单元格通过JSON调用获取内容。每个单元格都有一个滚动视图(图像幻灯片)。我注意到幻灯片是在旧的幻灯片上加载的(我可以看到旧单元格中的幻灯片在加载新幻灯片之前出现)。或者,如果我滑动第一个单元格的第三个图像,然后滚动第四个单元格,它会显示第三个图像(而不是第一个),但页面控件会显示这是第一张幻灯片 在生成新单元格时,如何“清除”旧单元格(或至少清除滚动视图,或阻止其被重用) 第h条(对象) Article.m(NSObject) 集合视图控制器 - (void)se

我有一个集合视图控制器,其中的单元格通过JSON调用获取内容。每个单元格都有一个滚动视图(图像幻灯片)。我注意到幻灯片是在旧的幻灯片上加载的(我可以看到旧单元格中的幻灯片在加载新幻灯片之前出现)。或者,如果我滑动第一个单元格的第三个图像,然后滚动第四个单元格,它会显示第三个图像(而不是第一个),但页面控件会显示这是第一张幻灯片

在生成新单元格时,如何“清除”旧单元格(或至少清除滚动视图,或阻止其被重用)

第h条(对象)

Article.m(NSObject)

集合视图控制器

- (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;
}