iPhone自定义绘制的UITableViewCell,如何加载+插入网页中的图像在线程中?
我一直在绘制自定义表格单元格(使用苹果的样本作为基础),现在必须做一个显示来自URL的图像的单元格 - 每个单元格将具有不同的图像(基于某些数据它有),但所有的单元格是相同的,所以相同的重用ID。iPhone自定义绘制的UITableViewCell,如何加载+插入网页中的图像在线程中?
这样做的正确结构是什么?很明显,我需要在新线程中加载图像。我有以下功能到目前为止坐在细胞查看它在自己的线程运行的类:
- (void)loadImage
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
self.img = [UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString: [myProduct objectForKey:@"ImagePath"]]]];
[self setNeedsDisplay];
[pool release];
}
当我把这个从drawRect中函数本身(这是坏的),那么它“作品”,但每当发生任何事情时(选择等),这显然都会被调用。如果我把它放在单元格uiview的init函数中,那么它只会被前面8个单元调用,然后它们会被重用。其他的变化最终导致图像在重用时没有得到“重置”,所以相同的8张图像在表格中重复(尽管其他文本更新)。
我暂时不担心缓存,但是有没有关于如何做到这一点的任何示例,或者任何人都可以指向正确的方向?谢谢。
那么,当您将单元出列时,您可以强制加载图像。您不必到init内做到这一点......通常这样做:
cell = dequeueCell...
if (!cell) {
//create one
}
return cell;
你可以做的是恢复单元之前,您可以强制图像加载,如果它是你想要的细胞类型。这样,无论何时显示,您都可以从缓存中抓取它(如果存在),如果不存在,请访问网站。
该解决方案将不得不更复杂,因为默认情况下,UITableView回收单元格(当一个滚动顶部时,它将移动到底部并用新数据重新配置)。因此,您可能会开始下载图像,但在下载完成之前单元格的内容已更改。
在cellForRowAtIndexPath:
,你应该从缓存(你的myProduct对象,一个NSArray,无论)中获取图像。如果它不在那里,你应该检查一个标志,看看它是否已经被加载。如果它尚未被加载,那么你设置该标志并分离一个新线程(你应该看看NSOperation
,它会排队工作,并保护你一次启动太多的线程)。
在你的线程中,你应该下载图像,然后使用performSelectorOnMainThread:target:waitUntilDone:
在图像的主线程上调用一个方法。该方法可以更新缓存,将isLoading标志设置为NO,并更新单元。这样做很重要,因为Cocoa要求您的所有UI更新代码都在主线程中。
我希望这是一个有用的提纲。
谢谢,这有助于。我看了一下stanford系列的线程flickr tableview代码,它帮助了我。目前通过执行cell.image = [cachedImg:url],然后触发NSOperation,然后执行一个reloadData tableview完成后,但我很想使用自定义绘图与其他单元格一样 - 我会怎么做呢? 我需要将图像传递给单元类,它将其传递给它的视图类,然后调用setNeedsDisplay?我如何引用由performSelectorOnMainThread调用的方法中的原始单元格? – Tom 2009-11-15 20:27:31
我发现一个非常好的方法是将NSOperations与NSNotifications结合使用 - 您可以让一个单元格订阅图像加载通知,从而完全加载图像。您可以附加像图像URL之类的东西,以确保您获取的通知与您正在等待的图像相关,并在prepareForReuse中取消订阅,以便在发送通知时仅更改可见单元格。 – 2009-11-15 20:52:15
如果您还没有看到明确的文档从苹果到UIImage的是线程安全的我不效应我认为你应该这样做。取而代之的是将你的图像作为NSData,并在主线程中将其转换为UIImage。基本规则是所有UIKit工作必须在主线程中完成,否则行为未定义。
我该如何处理线程位?我可以调用cellforrowatindexpath中的线程去获取图像,但是在那个时候,细胞已经绘制了自己(减去图像),然后我需要再次在细胞视图上调用setNeedsDisplay? – Tom 2009-11-15 17:49:23