繁体   English   中英

UICollectionView中的GCD和单元重用

[英]GCD and cell reuse in UICollectionView

我有一个自定义UICollectionViewCellUICollectionView实现。 从互联网获取数据阵列,但是当用户访问内容时下载图像。

虽然这可能不是最有效的方式,我不打算以这种方式离开它,它确实暴露了我正在努力解决的某个问题。 看起来细胞正在显示“缓存”或“旧”图像,当我慢慢滚动集合视图时,细胞图像不断变化。

这可能是一个问题,实际的细胞图像在那个时刻无法从网上获得,我的问题是如何强制空单元格或某些加载活动监视器而不显示不正确的图像?

提前谢谢,小齿轮

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * CellIdentifier = @"Event";

EventCollectionViewCell *cell  = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];


NSString *title = [[events objectAtIndex:indexPath.item] objectForKey:@"title"];
NSString *imageUrl = [[[events objectAtIndex:indexPath.item] objectForKey:@"photo"] objectForKey:@"url"];


dispatch_queue_t imageFetchQ = dispatch_queue_create("image fetched", NULL);
dispatch_async(imageFetchQ, ^{

    NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]];

    if (imageData)
    {

        dispatch_async(dispatch_get_main_queue(), ^{

            cell.eventImage.image = [UIImage imageWithData:imageData];
            cell.eventTitle.text = title;

        });
    }
});


return cell;

}

这是一个常见问题。 最大的问题是,当细胞图像到达时,细胞可能已被回收并可用于其他一些物品。 如果您尝试为单元格设置图像,则图像最终可用,您很可能会为错误的项目设置图像。

因此,不要尝试直接更新单元格。 甚至不要在图像下载完成块中保留对单元格的引用。 相反,让完成块更新数据模型,无论看起来如何。 您还可以对集合视图保持弱引用,并存储单元格的索引路径。 当图像到达时,完成代码可以调用-reloadItemsAtIndexPaths: ,如果单元格仍然可见,这将导致集合视图重新加载受影响的索引路径的单元格。 你的-collectionView:cellForItemAtIndexPath:方法只是做它常用的事情,但这次图像将在数据模型中可用。

所以,你的代码看起来像:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString * CellIdentifier = @"Event";
    EventCollectionViewCell *cell  = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];

    Event *event = [events objectAtIndex:indexPath.item];  // replace "Event" with whatever class you use for your items
    cell.eventTitle.text = [event objectForKey:@"title"];
    cell.eventImage.image = [event objectForKey:@"image"];
    if (cell.eventImage.image == nil) {
        NSString *imageUrl = [[[events objectAtIndex:indexPath.item] objectForKey:@"photo"] objectForKey:@"url"];

        dispatch_queue_t imageFetchQ = dispatch_queue_create("image fetched", NULL);
        dispatch_async(imageFetchQ, ^{
            __weak UICollectionView *weakCollection;
            NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]];
            UIImage *image = [UIImage imageWithData:imageData];
            if (image)
            {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [event setObject:image forKey:@"image"]; // updating the model here
                    [weakCollection reloadItemsAtIndexPaths:@[indexPath]];
                });
            }
        });
    }
    return cell;
}

我没有测试过这个确切的代码,因为我不知道你的数据模型是什么样的。 请务必将您自己的数据项类替换为我假设的Event类。 但是,我在自己的代码中使用相同的技术,我认为这是正确的方法。 亮点:

  • 更新数据模型中的图像意味着下次需要显示项目时它将可用,即使在下载图像时该项目不可见。
  • 如果用户导航离开集合视图时图像仍然到达,则使用对集合视图的弱引用可以避免出现问题。
  • 调用-reloadItemsAtIndexPaths:有助于将单元格的更改限制为...cellForItemAtIndexPath:方法。

需要注意的是,如果您正在显示的事物列表可能会发生变化(例如,如果用户可以随时间添加或删除项目),那么您的完成代码依赖于保持不变的索引路径甚至可能是不安全的。 在这种情况下,您需要在图像到达时确定项目的索引路径。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM