NSURLConnection与NSData + GCD

时间:2011-09-14 19:22:24

标签: objective-c ios nsurlconnection grand-central-dispatch

NSData总是有一个非常方便的方法+dataWithContentsOfURL:options:error:。虽然方便,但它也会阻止当前线程的执行,这意味着它对生产代码基本无用(忽略NSOperation)。我很少使用这种方法,我完全忘记了它的存在。直到最近。

我从管中获取数据的方式是标准的NSURLConnectionDelegate方法:编写一个处理各种NSURLConnectionDelegate方法的下载类,逐步构建一些数据,处理错误等。我通常会使这个通用足以重复使用尽可能多的请求。

假设我的典型下载程序类在100行的球场中运行。这是100行异步执行NSData可以在一行中同步执行的操作。为了更复杂,该下载程序类需要一个自己的委托协议来向其所有者传达完成和错误,并且所有者需要以某种方式实现该协议。

现在,进入Grand Central Dispatch,我可以做一些非常简单的事情:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {

    NSData* data = [NSData dataWithContentsOfURL:someURL];
    // Process data, also async...

    dispatch_async(dispatch_get_main_queue(), ^(void) {
        // Back to the main thread for UI updates, etc.
    });
});

我可以把这个傻瓜扔进我想要的任何地方,就行了。无需下载类,无需处理连接委托方法:只需几行即可轻松实现异步数据。这种方法与我之前的GCD方法之间的差异非常大,足以触发“真正的警报”。

因此,我的问题:使用NSData + GCD进行简单的数据下载任务而不是NSURLConnection是否有任何警告(假设我不关心下载进度等事情)?

3 个答案:

答案 0 :(得分:22)

你在这里失去了很多功能:

  • 无法遵循下载进度
  • 无法取消下载
  • 无法管理可能的身份验证过程
  • 你无法轻易处理错误,这是非常重要,尤其是在iPhone上的移动开发中(当然,因为你经常在真实条件下失去你的网络,所以追踪这样的错误非常重要)开发适用于iOS的网络错误案例)

我想的可能还有更多。


正确的方法是创建一个类而不是管理下载。

例如,请参阅我自己的OHURLLoader类,这很简单,我使API易于使用块:

NSURL* url = ...
NSURLRequest* req = [NSURLRequest requestWithURL:url];

OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req];
[loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) {
    NSLog(@"Download of %@ done (statusCode:%d)",url,httpStatusCode);
    if (httpStatusCode == 200) {
        NSLog(%@"Received string: %@", loader.receivedString); // receivedString is a commodity getter that interpret receivedData using the TextEncoding specified in the HTTP response
    } else {
        NSLog(@"HTTP Status code: %d",httpStatusCode); // Log unexpected status code
    }
} errorHandler:^(NSError *error) {
    NSLog(@"Error while downloading %@: %@",url,error);
}];

有关详细信息,请参阅github上的README file和示例项目。

这样:

  • 你仍然依赖NSURLConnection提供的异步方法(和 as the Apple's documentation says about Concurrency Programming ,如果已经存在API来进行异步任务,如果可能的话,使用它而不是依赖于另一种线程技术)< / LI>
  • 你保留了NSURLConnection(错误处理等)的优点
  • 但您还拥有块语法的优点,使您的代码比使用委托方法时更具可读性

答案 1 :(得分:12)

<强> WWDC 2010 Session Videos

  • WWDC 2010 Session 207 - 适用于iPhone OS的网络应用,第1部分
  • WWDC 2010 Session 208 - 适用于iPhone OS的网络应用,第2部分

讲师说

  

“线程是邪恶的”。

对于网络编程,强烈建议在RunLoop中使用异步API。

因为,如果你使用NSData + GCD,如下所示,它每个连接使用一个线程。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
    NSData* data = [NSData dataWithContentsOfURL:someURL];

它可能会使用许多连接和许多线程。使用GCD太容易了:-) 然后,许多线程为其堆栈占用了大量内存。 因此,你最好使用异步API,就像AliSoftware所说的那样。

答案 2 :(得分:2)

从OS X v10.9和iOS 7开始,首选方法是使用NSURLSession。它为您提供了一个漂亮的基于块的界面,以及取消,暂停和后台下载等功能。