从文档目录异步加载图像到UICollectionView

问题描述:

我想从文档目录加载图像到UICollectionView。它的工作原理:平稳,快速....(大声笑)。但我得到一个问题:当我打电话[collectionView reloadData],图像闪烁(一次)。这里是我的代码:从文档目录异步加载图像到UICollectionView

- (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView_ cellForItemAtIndexPath:(NSIndexPath *)indexPath { 
    NSString *cellIdentifier = NSStringFromClass([AFMyRecentCollectionViewCell class]); 
    AFMyRecentCollectionViewCell *cell = (AFMyRecentCollectionViewCell*)[collectionView_ dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath]; 
    AFMyRecentObject *recent = [[AFRecentManager sharedInstance].arrayRecent objectAtIndex:indexPath.row]; 

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul); 
    dispatch_async(queue, ^{ 
     UIImage *image; 
     NSFileManager *fileManager = [NSFileManager defaultManager]; 
     NSString *filePath = [self databasePathWithPathComponent:[NSString stringWithFormat:@"%@.jpg", recent.id_film]]; 
     if ([fileManager fileExistsAtPath:filePath] == YES) { 
      image = [UIImage imageWithContentsOfFile:filePath]; 
     } 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      if (image) { 
       cell.imageView.image = image; 
      } else { 
       cell.imageView.image = [UIImage imageNamed:@"loadding.png"]; 
      } 
     }); 
    }); 

    cell.layer.shouldRasterize = YES; 
    cell.layer.rasterizationScale = [UIScreen mainScreen].scale; 

    return cell; 
} 

- (NSString *)databasePathWithPathComponent:(NSString*)pathComponent { 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex: 0]; 
    NSString *path = [documentsDirectory stringByAppendingPathComponent:pathComponent]; 
    return path; 
} 
+0

顺便说一句,你在技术上应该确保了'cell'还没有被重新用于另一个'NSIndexPath' 'UIImage'被实例化的时间。很可能,因为你从本地存储中检索,这不太可能是个问题,但是如果你要发起任何网络请求,那么在蜂窝网络上快速滚动时突然变成一个非常实际的问题。因此,要非常小心地使用上述模式,除非您确信在异步更新过程中单元格不能重新使用。 – Rob

我面临flickring &解决它使用以下方法图像的同样的问题。

应用相同的延迟加载概念。像创建一个字典对象来存储显示之前的所有图像,在从文档目录获取图像之前,检查字典中是否存在图像,如果它存在,则使用该图像来显示它。

如果图像不在字典中,那么做数据库操作。

希望这可以解决您的问题。

+0

感谢您的评论。有用。 – TienLe

+1

如果你这样做,我会推荐(a)'NSCache'而不是字典;和(b)确保你在接收到内存警告时清除这个数据结构。还要注意,这并没有达到问题的根源,即在启动异步调用之前未能初始化'image'属性。 – Rob

+0

@Rob:我还没有使用过NSCache。我会尝试使用它。感谢您的支持。 – TienLe

问题是,您正在启动图像视图的异步更新,但是如果单元格被重用,您将在那里看到旧图像。因此,在您检索图像之前dispatch_async,请确保您先将cell.imageView.image设置为nil。因此,请确保在启动正确图像的异步检索之前,您不会在单元格中看到之前的图像。

你必须放置和默认/图像占位符,以防止..

// this prevents the flicker/blinks 
    cell.imageView.image = nil; // if you dont have any image as placeholder 

    //since you have 
    cell.imageView.image = [UIImage imageNamed:@"loadding.png"]; // this i assume your placeholder image? 

    dispatch_async(queue, ^{ 
     //your codes.. 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      // your codes.. 
     }); 
    });