NSURLConnection 是不是阻塞 Main/UI 线程
Posted
技术标签:
【中文标题】NSURLConnection 是不是阻塞 Main/UI 线程【英文标题】:Does NSURLConnection Block the Main/UI ThreadNSURLConnection 是否阻塞 Main/UI 线程 【发布时间】:2010-07-13 03:47:23 【问题描述】:当它们滚动到屏幕上时,我正在下载表格视图单元格中的图像。出于用户体验的原因,我开始下载- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
中的图像。我不会等到表格视图完成滚动。设置表格视图单元格后,我开始下载我还没有的图像。但是,在表格视图停止移动之前,它们似乎并没有完全下载。一旦它停止移动,图像几乎会立即下载。
有没有在主 UI 线程不阻塞的情况下使用 NSURLConnection?或者,有没有一种方法可以在滚动表格视图时快速下载这些图像。
** 编辑 **
为了证明 NSURLConnection 比较慢,我使用 NSThread 在不同的线程中分离一个新的选择器。然后我下载数据并回调到创建 UIImage 并将其显示在表视图中的主线程。这种方法工作得更快。
就个人而言,我认为 NSURLConnection 被扔进了 UITableView 滚动阻止它的事件循环中。
【问题讨论】:
用户滚动表格的速度比手机访问网络和下载图像的速度要快得多。对我来说听起来很正常... 我刚刚通过分离一个新的 NSThread 实现了相同的解决方案,它的下载速度要快得多。 下载肯定会使用事件循环。滚动以某种方式将其关闭,这听起来似乎是合理的。 【参考方案1】:阅读NSDefaultRunLoopMode vs NSRunLoopCommonModes 可以很好地解释为什么所有下载委托通知都排队,但是在使用主线程时滚动时下载从这里改变:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
到这里:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self
startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSRunLoopCommonModes];
[connection start];
【讨论】:
【参考方案2】:我以前遇到过这个问题。滚动视图时,NSURLConnection 的异步委托方法不会触发。虽然下载在后台进行,但您的主线程不会收到新图像的通知。就像你一样,我相信这个问题与在具有不同 RunLoopMode 的内部 NSRunLoop 中滚动的滚动视图有关。我一直在与 Apple 员工讨论这个问题,并让他们查看我的代码,但我们无法找到解决方案。
另一方面,Jeff LaMarche 在他的博客上有this post,他在那里做同样的事情,并且按预期工作。我一直无法弄清楚他的不同之处(主要是因为没有时间),但这可能值得一看。
【讨论】:
【参考方案3】:如果您的意思是“NSURLConnection 是否在主线程上执行?”,那么是的,我相信是这样。打开连接并在主线程上执行委托方法。我没有找到任何其他建议的文档,您可以通过调试来验证它。
我认为您认为 UITableView 滚动阻止主运行循环中的 NSURLConnection 回调的假设是正确的。
您已经发布了一个解决方案,为您的选择器生成了一个线程。另一种选择是将下载作为 NSOperations 执行,这有几个好处:
如果您强制操作同时运行(请参阅Dave Dribin's excellent post on this),您可以限制同时下载的数量,如果您的表中有大量图像,这可能是可取的。您说您的下载“几乎立即”发生,但如果您的用户连接速度较慢并且您的表格包含大量图像,则情况可能并非如此。 如果用户做了一些使图片下载无关紧要的事情,例如执行另一个搜索,您可以取消所有操作。我使用的是 Dave Dribin 的方法,它强制连接在主线程上执行,但这对于您的目的可能不是必需的 - 您可以使用当前的方法在图像之后回调主线程下载。
【讨论】:
【参考方案4】:听起来您正在同步下载。
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html#//apple_ref/doc/uid/20001836-170129
阅读并确保您使用的是异步 API
【讨论】:
我绝对没有使用同步 API。我认为 NSURLConnection 被扔进了事件循环,而 UITableView 一直在那个循环中占用。以上是关于NSURLConnection 是不是阻塞 Main/UI 线程的主要内容,如果未能解决你的问题,请参考以下文章
NSURLConnection 是不是利用了 NSURLCache?