gpt4 book ai didi

ios - UICollectionView 中的 GCD 和单元格重用

转载 作者:可可西里 更新时间:2023-11-01 05:36:40 27 4
gpt4 key购买 nike

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

虽然这可能不是最有效的方法,而且我也不打算就此保留,但它确实暴露了我正在努力解决的某个问题。似乎单元格正在显示“缓存”或“旧”图像,当我慢慢滚动 Collection View 时,单元格图像不断变化。

这可能是一个问题,因为当时无法从网络上及时获得实际细胞图像,我的问题是如何强制使用空细胞或某些加载事件监视器而不显示不正确的图像?

提前致谢,小齿轮

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

}

最佳答案

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

所以,不要尝试直接更新单元格。甚至不要在图像下载完成 block 中保留对单元格的引用。相反,让完成 block 更新数据模型,不管它是什么样子。您还可以保留对 Collection View 的弱引用,并存储单元格的索引路径。当图像到达时,完成代码可以调用 -reloadItemsAtIndexPaths:,如果单元格仍然可见,这将导致 Collection View 重新加载受影响的索引路径的单元格。您的 -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 类。但是,我在自己的代码中使用了相同的技术,我认为这是正确的方法。亮点:

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

需要注意的是,如果您显示的内容列表可以更改(例如,如果用户可以随着时间的推移添加或删除项目),那么您的完成代码甚至可能不安全地依赖索引路径保持不变相同。在这种情况下,您需要在图像到达时确定项目的索引路径。

关于ios - UICollectionView 中的 GCD 和单元格重用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16273876/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com