[英]GCD and cell reuse in UICollectionView
我有一個自定義UICollectionViewCell
的UICollectionView
實現。 從互聯網獲取數據陣列,但是當用戶訪問內容時下載圖像。
雖然這可能不是最有效的方式,我不打算以這種方式離開它,它確實暴露了我正在努力解決的某個問題。 看起來細胞正在顯示“緩存”或“舊”圖像,當我慢慢滾動集合視圖時,細胞圖像不斷變化。
這可能是一個問題,實際的細胞圖像在那個時刻無法從網上獲得,我的問題是如何強制空單元格或某些加載活動監視器而不顯示不正確的圖像?
提前謝謝,小齒輪
-(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.