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发送网络请求

Swift3.0:NSURLConnection的使用

NSURLConnection 是不是保留其委托?

NSURLConnection 是不是利用了 NSURLCache?

NSURLConnection 发送 GET 请求而不是 POST 请求

NSURLConnection 返回错误而不是响应 401