UITableViewCell 线程中的图像缓存

Posted

技术标签:

【中文标题】UITableViewCell 线程中的图像缓存【英文标题】:Image cacheing in thread for UITableViewCell 【发布时间】:2011-09-09 22:57:32 【问题描述】:

我有一个图像缓存类,它将个人资料图像存储在 NSMutableDictionary 中。如果key存在,则缓存返回一个UIImage对象,如果不存在,则下载它,将其存储在字典中,并返回UIImage。这个共享缓存在 NSThreaded 方法中调用,如下所示:

[NSThread detachNewThreadSelector:@selector(setImageForUser:) toTarget:self withObject:imageUrlString];

-(void)setImageForUser:(NSString *)imageUrlString 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    LPImageCacher *imageCache = [LPImageCacher sharedCache];
    UIImage *profileImg = [imageCache getCachedImageFromMemory:imageUrlString];
    self.userProfileImageView.image = profileImg;
    if (profileImg == nil) 
        imageUrlString = [[myGlobals sharedInstance].avatarUrlDefault stringByAppendingString:@"/avatar.png"];
        self.userProfileImageView.image = [imageCache getCachedImageFromMemory:imageUrlString];
    

    [pool release];

问题是,如果他们在加载任何内容之前滚动 UITableView,图像会积压,然后最终所有图像都会被加载,它们会在当前单元格上闪烁并更改,直到到达正确的单元格。我认为在每个单元格中创建一个 NSThread 实例并在 -prepareForReuse 中取消线程会很好,但我似乎无法再次重用 NSThread 对象,关于如何解决这个问题的任何想法?

【问题讨论】:

【参考方案1】:

我认为您看到的问题是由于 UIScrollView 在您滚动时“冻结”所有内容。这是一个运行循环问题。为了解决这个问题,您需要确保在默认运行循环中发送 -setImageForUser: 消息。

查看这些资源以获取更多信息:

NSURLRequest won't fire while UIScrollView is scrolling

UIScrollView pauses NSTimer until scrolling finishes

希望这会有所帮助!

【讨论】:

【参考方案2】:

里德奥尔森给了你直接的答案。我想提一件事。

为每个单元分配线程的成本相当高,为什么不使用NSOperationQueue?您可以有一组工作线程来执行每个单独的加载,并且将这个队列的功能限制为随时可见单元的最大数量是有意义的。这几乎是“重用线程”。

事实上,我建议使用ASIHTTP 的ASINetworkQueue。它比 NSOperationQueue 使用起来更简单。

此外,请尝试添加一个简单的优化,以便在滚动速度低于某个数字时加载单元格。当您无法停下来查看图像时,为什么还要加载图像?例如,我为 tableView 写了这样的东西:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView

    static float prevOffset = 0.0;
    static float scrollSpeed = 0.0;

    // positive -> downwards
    scrollSpeed = scrollView.contentOffset.y - prevOffset;

    if (scrollSpeed < 2.0)
    
        [self loadImagesForVisibleCellsInTableView:(UITableView*)scrollView];
    
    else if (scrollSpeed < 6.0)
    
        shouldLoadImages = YES;
    
    else
    
        shouldLoadImages = NO;
    

    prevOffset = scrollView.contentOffset.y;

这会在 tableView 快速移动时忽略加载新图像(shouldLoadImages 影响 tableView:cellForRowAtIndexPath,告诉他们忽略加载图像)并且当它即将停止时,它会强制重新加载可见单元格。

【讨论】:

【参考方案3】:

您应该使用主线程将屏幕更新给用户。这个Common multithreading mistakes beginners make on iPhone 将帮助您确定问题。

【讨论】:

以上是关于UITableViewCell 线程中的图像缓存的主要内容,如果未能解决你的问题,请参考以下文章

UITableViewCell重用后加载不正确的图像

检查设置的图像是不是与缓存中的图像相同

UITableViewCell 中的 UIScrollview 和维护滚动视图页面

UITableViewCell 上的 PFImageView 断断续续的滚动

在自定义 uitableviewcell 中设置图像会导致延迟

在 UITableviewCell 中的气泡上显示图像