iOS7 Networking with NSURLSession: Part 1

From a developer's perspective, one of the more significant changes in iOS 7, and OS X Mavericks for that matter, is the introduction of NSURLSession. Even thoughNSURLSession may seem daunting at first glance, it's important that you understand what it is, how it relates to NSURLConnection, and what the differences are. In this series, I will take you through the fundamentals of NSURLSession so you can take advantage of this new technology in your own applications.

从开发者的角度,对于iOS7和OS X Mavericks最显著的变化就是引入了 NSURLSession 。虽然乍一看,NSURLSession 有点令人生畏,但重要的是要了解它是什么,它和 NSURLConnection 有什么关系和差异。在本系列 Networking with NSURLSession 教程中,我将会带你了解 NSURLSession 有关的基本内容,你也可以在你的应用程序中使用这种新技术的优势。

Why Replace NSURLConnection?

The first question you may be asking yourself is why Apple found it necessary to introduce NSURLSession while we are perfectly happy with NSURLConnection. The real question is whether you are happy with NSURLConnection. Do you remember that time you were cursing and throwing things at NSURLConnection? Most Cocoa developers have been in that place, which is why Apple decided to go back to the drawing board and create a more elegant solution, better suited for the modern web.

你可能会问这样一个问题:为什么正当我们愉快的使用 NSURLConnection的时候,有必要引入 NSURLSession 吗?然而,问题恰恰就在于,你是否真的使用 NSURLConnection 很愉快?莫非你忘了你曾经咒骂吐槽 NSURLConnection 了,没错,大多数 Cocoa 开发者曾有这样的经历,所以Apple才决定重新设计一种更优雅的解决方案以适应于现代网络开发。

Even though NSURLSession and NSURLConnection have a lot in common in terms of how they work, at a fundamental level, they are quite different. Apple created NSURLSessionto resemble the general concepts of NSURLConnection, but you will learn in the course of this series that NSURLSession is modern, easier to use, and built with mobile in mind.

尽管 NSURLSession 和 NSURLConnection 的运行有很多共同点,但是在最基础的层面上,它们还是有着很大的不同。Apple 引入类似于 NSURLConnection 概念的 NSURLSession ,你将会在本系列 Networking with NSURLSession 教程的这篇文章中了解到 NSURLSession 是现代的,更易于使用的,而且是附有为移动应用设计的初衷。

What is NSURLSession?

Before I discuss the differences between NSURLSession and NSURLConnection, it's a good idea to first take a closer look at what NSURLSession is. Despite its name,NSURLSession isn't just another class you can use in an iOS or OS X application.NSURLSession is first and foremost a technology just like NSURLConnection is.

在讨论 NSURLSession 和 NSURLConnection 的不同之处之前,不妨先仔细了解一下 NSURLSession 是什么。对于 NSURLSession ,它仅仅是可以在 iOS 和 OS X应用程序中使用的一个类,其就像 NSURLConnection 一样是一种用于网络开发的技术。

Sessions are Containers

NSURLSession and NSURLConnection both provide an API for interacting with various protocols, such as HTTP and HTTPS. The session object, an instance of theNSURLSession class, is what manages this interaction. It is a highly configurable container with an elegant API that allows for fine-grained control. It offers features that are absent in NSURLConnection. What's more, with NSURLSession, you can accomplish tasks that are simply not possible with NSURLConnection, such as implementing private browsing.

NSURLSession 和 NSURLConnection 都提供了与各种协议,诸如 HTTP 和 HTTPS ,进行交互的API。会话对象,NSURLSession 类对象,就是用于管理这种交互过程。它是一个高度可配置的容器,通过使用其提供的APPI,可进行细粒度的管理控制。它提供了在 NSURLConnection 中的所有特性,此外,它还可以实现 NSURLConnection 不能完成的任务,例如实现私密浏览。

Tasks

The basic unit of work when working with NSURLSession is the task, an instance ofNSURLSessionTask. There are three types of tasks, data tasksupload tasks, anddownload tasks.

使用 NSURLSession 最基本单元就是任务(task),这个是 NSURLSessionTask 的实例。有三种类型的任务:data task,upload task 和 download task。

                     

  • You'll most often use data tasks, which are instances of NSURLSessionDataTask. Data tasks are used for requesting data from a server, such as JSON data. The principal difference with upload and download tasks is that they return data directly to your application instead of going through the file system. The data is only stored in memory.
最常使用的就是 Data task,它是 NSURLSessionDataTask 的实例。Data task 是用于从服务器上请求数据,例如 JSON 数据。它和 Upload task 和 Download task 的主要区别是它直接返回数据给应用程序,而非通过文件系统。这些数据只存储在内存中。
  • As the name implies, upload tasks are used to upload data to a remote destination. The NSURLSessionUploadTask is a subclass of NSURLSessionDataTaskand behaves in a similar fashion. One of the key differences with a regular data task is that upload tasks can be used in a session created with a background session configuration.
顾名思义,Upload task 是用来将数据上传到远程的目标。NSURLSessionUploadTask 是 NSURLSessionDataTask 的子类,而且行为也类似。其中一个主要的区别于普通的Data task的是 Upload task 可以在后台会话管理中使用。
  • Download tasks, instances of NSURLSessionDownloadTask, inherit directly fromNSURLSessionTask. The most significant difference with data tasks is that a download task writes its response directly to a temporary file. This is quite different from a regular data task that stores the response in memory. It is possible to cancel a download task and resume it at a later point.
Download task,NSURLSessionDownloadTask 的实例,直接继承自 NSURLSessionTask。和Data task最显著的区别是 Download task 将其响应数据写入临时文件中,而 Data task 只是将其响应数据保存在内存中。Download task 可以取消,也可以在稍后进行恢复。

As you can imagine, asynchronicity is a key concept in NSURLSession. TheNSURLSession API returns data by invoking a completion handler or through the session's delegate. The API of NSURLSession was designed with flexibility in mind as you'll notice a bit later in this tutorial.

正如你所想的,异步性是NSURLSession的关键概念。使用 NSURLSession 的 API 返回数据可以通过调用完成处理程序块或者通过会话的委托。NSURLSession 的 API 在设计的时候充分考虑了灵活性,关于这一点,你将会在本教程的后面体会到。

Meet the Family

As I mentioned earlier, NSURLSession is both a technology and a class that you'll be working with. The NSURLSession API houses a number of classes, but NSURLSession is the key component sending requests and receiving responses. The configuration of the session object, however, is handled by an instance of the NSURLSessionConfigurationclass. The NSURLSessionTask class and its three concrete subclasses are the workers and are always used in conjunction with a session as it is the session that creates the task objects.

正如我之前提到的,NSURLSession 即是指一种新的网络开发技术,同时也是一个类。NSURLSession 的 API 包括若干个类,但是 NSURLSession 是关键的部件用于发送请求和接收响应,而会话对象的配置是由 NSURLSessionConfiguration 实例进行处理。NSURLSessionTask 和其三个具体的子类总是和会话对象关联在一起,因为会话对象创建了任务对象。

Delegation

Both NSURLSession and NSURLConnection rely heavily on the delegation pattern. TheNSURLSessionDelegate protocol declares a handful of delegate methods for handling events at the session-level. In addition, the NSURLSessionTask class and subclasses each declare a delegate protocol for handling task-level events.

NSURLSession 和 NSURLConnection 都采用了委托代理模式。NSURLSessionDelegate 委托协议声明了少量的委托方法用于处理会话事件。除此之外,NSURLSessionTask 和其子类都各自有一个委托协议用于处理任务事件。

Old Friends

The NSURLSession API builds on top of classes that you're already familiar with, such asNSURLNSURLRequest, and NSURLResponse.

NSURLSession 的 API 的使用涉及到你曾熟悉的类,例如:NSURL,NSURLRequest 和 NSURLResponse。

What are the differences?

How does NSURLSession differ from NSURLConnection? This is an important question, because NSURLConnection is not being deprecated by Apple. You can still useNSURLConnection in your projects. Why should you use NSURLSession?

那么 NSURLSession 和 NSURLConnection 有什么不同呢?这是一个关键的问题,因为 NSURLConnection 还未被 Apple 弃用。你仍可以是项目中使用 NSURLConnection。那何时使用 NSURLSession 呢?

The first thing to understand is that the NSURLSession instance is the object that manages the request and response. This is similar to how NSURLConnection works, but the key difference is that the configuration of the request is handled by the session object, which is a long lived object. This is done through the NSURLSessionConfigurationclass. Not only does it provide the NSURLSession API fine-grained configuration through the NSURLSessionConfiguration class, it encourages the separation of data (request body) from metadata. The NSURLSessionDownloadTask illustrates this well by directly writing the response to the file system.

首先要了解到,NSURLSession 实例对象是管理请求和响应的,这和 NSURLConnection 相似,但区别是管理请求配置的是一个长寿命对象,由 NSURLSessionConfiguration 类对象完成。通过 NSURLSessionConfiguration 类不仅提供了细粒度配置的 API 管理 NSURLSession 会话对象,而且将数据(请求主体)从元数据(metadata)中分离开来。NSURLSessionDownloadTask 通过直接将响应数据写入文件系统就很好的说明了这一点。

Authentication is easier and handled more elegantly by NSURLSession. TheNSURLSession API handles authentication on a connection basis instead of on a request basis, like NSURLConnection does. The NSURLSession API also makes it more convenient to provide HTTP options and each session can have a separate storage container depending on how you configure the session.

通过 NSURLSession 可以更容易的实现身份认证。NSURLSession 的 API 处理身份认证是在连接的基础上进行而非在请求的基础上进行,和 NSURLConnection 的处理方式是一样的。NSURLSession 的 API 提供了方便的 HTTP 协议处理选项,而且每一个会话可以根据你是如何配置会话而有一个单独的存储容器。

In the introduction, I told you that NSURLSession provides a modern interface, which integrates gracefully with iOS 7. One example of this integration is NSURLSession's out-of-process uploads and downloads. NSURLSession is optimized to preserve battery life, supports pausing, canceling, and resuming of tasks as well as UIKit's multitasking API. What is not to love about NSURLSession?

在引言中,我告诉你 NSURLSession 提供了一个现代化的接口,它与iOS 7优雅的集成整合。这种集成整合体现的一个例子是 NSURLSession 的上传下载是在进程外进行。 NSURLSession 也进行了优化以保持电池的使用寿命,提供暂停,取消和恢复任务,还支持 UIKit 的多线程处理的 API 。还有什么理由不爱 NSURLSession 呢?

Getting Your Feet Wet

Step 1: Project Setup

A new API is best learned by practice so it's time to fire up Xcode and get our feet wet. Launch Xcode 5, create a new project by selecting New > Project... from the Filemenu, and select the Single View Application template from the list of iOS application templates.

实践出真知。在 Xcode 5 中创建一个单视图项目。


Give your project a name, tell Xcode where you'd like to save it, and hit Create. There's no need to put the project under source control.


Step 2: Create a Session Object

When working with NSURLSession, it is important to understand that the session object, an instance of NSURLSession, is the star player. It handles the requests and responses, configures the requests, manages session storage and state, etc. Creating a session can be done several ways. The quickest way to get started is to use NSURLSession'ssharedSession class method as shown below.

在使用 NSURLSession 的时候,重点是理解会话对象(它可是主角),NSURLSession 的实例。它处理请求和响应,配置请求,管理会话的存储和状态,等等。创建会话对象有多种方式,最快的是使用 NSURLSession 的 sharedSession 类方法。

- (void)viewDidLoad {
    [super viewDidLoad];
 
    NSURLSession *session = [NSURLSession sharedSession];
}

Create a session object in the view controller's viewDidLoad method as shown above. The session object we created is fine for our example, but you probably want a bit more flexibility in most cases. The session object we just created uses the globalNSURLCacheNSHTTPCookieStorage, and NSURLCredentialStorage. This means that it works pretty similar to a default implementation of NSURLConnection.

在视图控制器的 viewDidLoad 方法创建了 session 会话对象,这个会话对象已经适合我们例子的需要了,但是在大多数情况下可能需要多一点的灵活性。刚刚我们创建的 session 对象使用全局的 NSURLCache,NSHTTPCookieStorage 和 NSURLCredentialStorage。这样 session 的工作状态就和 NSURLConnection 的默认实现类似。

Step 3: Create a Data Task

To put the session object to use, let's query the iTunes Store Search API and search for software made by Apple. The iTunes Store Search API is easy to use and requires no authentication, which makes it ideal for our example.

为了测试 session 对象的使用,我们使用 Apple 提供的数据查询接口: iTunes Store Search API ,这个开发接口易于使用且不需要身份验证,适合本例子。

To query the search API, we need to send a request tohttps://itunes.apple.com/search and pass a few parameters. As we saw earlier, when using the NSURLSession API, a request is represented by a task. To query the search API, all we need is a data task, an instance of the NSURLSessionDataTask class. Take a look at the updated viewDidLoad implementation shown below.

我们发送请求并传递一些请求参数。正如我们之前所见,一个任务代表一个请求。使用查询接口请求数据,我们需要一个 Data task,NSURLSessionDataTask 的实例。修改 viewDidLoad 方法如下:

- (void)viewDidLoad {
    [super viewDidLoad];
 
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:@"https://itunes.apple.com/search?term=apple&media=software"]completionHandler:^(NSData *data,NSURLResponse *response,NSError *error) {
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSLog(@"%@", json);
    }];
}

There are a number of methods available to create a task, but the key concept to understand is that the session object does the actual creation and configuration of the task. In this example, we invoke dataTaskWithURL:completionHandler: and pass it an instance of NSURL as well as a completion handler. The completion handler accepts three arguments, the raw data of the response (NSData), the response object(NSURLResponse), and an error object (NSError). If the request is successful, the error object is nil. Because we know the request returns a JSON response, we create a Foundation object from the data object that we've received and log the output to the console.

有许多方法来创建一个任务,但是关键概念的理解是 session 对象创建且配置了任务。在这个例子中,我们调用  dataTaskWithURL:completionHandler: 方法,并传递 NSURL 对象和一个完成程序代码块作为参数。完成程序代码块有三个参数:请求响应的原始数据(NSData),响应对象(NSURLResponse)和一个错误对象(NSError)。如果请求成功,错误对象就为 nil。因为我们知道请求返回的是JSON数据作为响应,我们用 data 对象接收响应,并在终端中输出。

It is important to understand that the error object passed to the completion handler is only populated, not nil, if the request failed or encountered an error. In other words, if the request returned a 404 response, the request did succeed as far as the sessions is concerned. The error object will then be nil. This is an important concept to grasp when working with NSURLSession and NSURLConnection for that matter.

对于 error 对象,如果请求失败或者遇到一个错误,那么传递给完成处理代码块的 error 对象(不是nil)就很重要了。换言之,如果请求得到一个 404 的响应,那么请求将会直到会话连接成功才得到响应。当然 error 对象也有可能是 nil。所以在使用 NSURLSession 和 NSURLConnection 的时候 error 对象是一个很重要把握的概念。

Build the project and run the application in the iOS Simulator or on a physical device, and inspect Xcode's Console. Nothing is printed to the console. What went wrong? As I mentioned earlier, the NSURLSession API supports pausing, canceling, and resuming of tasks or requests. This behavior is similar to that of NSOperation and it may remind you of the AFNetworking library. A task has a state property that indicates whether the task is running (NSURLSessionTaskStateRunning), suspended(NSURLSessionTaskStateSuspended), canceling (NSURLSessionTaskStateCanceling), or completed (NSURLSessionTaskStateCompleted). When a session object creates a task, the task starts its life in the suspended state. To start the task, we need to tell it toresume by calling resume on the task. Update the viewDidLoad method as shown below, run the application one more time, and inspect the output in the console. Mission accomplished.

编译运行程序在模拟器或者真机,然后观察 Xcode 的终端,会发现没有东西输出。是否出错了呢?正如我之前所说,NSURLSession 的 API 支持暂停,取消和恢复请求任务。这个和 NSOperation 很相似。任务有一个 state 状态属性指示一个任务是否正在运行 (NSURLSessionTaskStateRunning),是否停止(NSURLSessionTaskStateSuspended),是否取消(NSURLSessionTaskStateCanceling)或者是否完成(NSURLSessionTaskStateCompleted)。当一个会话对象创建了一个任务,这个任务初始时是处于停止状态。为了启动任务,我们需要调用 resume 方法去启动任务执行。修改 viewDidLoad 方法如下,重新运行,观察终端中的输出。

- (void)viewDidLoad {
    [super viewDidLoad];
 
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:@"https://itunes.apple.com/search?term=apple&media=software"]completionHandler:^(NSData *data,NSURLResponse *response,NSError *error) {
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSLog(@"%@", json);
    }];
 
    [dataTask resume];
}

Downloading a Remote Resource

In the previous example, we made use of a completion handler to process the response we received from the request. It's also possible to achieve the same result by implementing the task delegate protocol(s). Let's see what it takes to download an image by leveraging NSURLSession and the NSURLSessionDownloadTask.

在前一个例子中,我们使用完成程序代码块去处理请求接收到的响应。也可以通过委托协议来实现相同过程。让我们看看借助 NSURLSession 和 NSURLSessionDownloadTask 完成下载图像。

Step 1: Create the User Interface

Open MTViewController.h and create two outlets as shown below. We'll use the first outlet, an instance of UIImageView, to display the downloaded image to the user. The second outlet, an instance of UIProgressView, will show the progress of the download task.

打开 MTViewController.h 然后创建如下的两个 outlet 。我们使用第一个 outlet,UIImageView 的实例,去显示下载的图像;第二个 outlet ,UIProgressView 的实例,去显示下载任务的进度。

#import <UIKit/UIKit.h>
 
@interface MTViewController: UIViewController
 
@property(weak,nonatomic)IBOutlet UIImageView *imageView;
@property(weak,nonatomic)IBOutlet UIProgressView *progressView;
 
@end

Open the project's main storyboard (Main.storyboard), drag a UIImageView instance to the view controller's view, and connect the view controller's outlet that we just created in the view controller's header file. Repeat this process for the progress view.

打开项目的 storyboard,拖动 UIImageView 到视图中,然后和视图控制器中的 outlet 进行连接对应。重复这个过程完成添加进度条。


译者注:由于添加进度条之后,其默认值为0.5(打开 Xcode 右侧栏 Attributes inspector,其中 Progress 值默认为 0.5),那么由于下载一开始是从 0 开始,那么应该修改设置其为 0。或者使用代码,在 viewDidLoad  方法中 增加如下代码进行设置:

    [self.progressView setProgress:0];

Step 2: Create a Download Task

In this example, we won't make use of the sharedSession class method, because we need to configure the session object that we'll use to make the request. Update the implementation of viewDidLoad as shown below.

在这个例子中,我们不使用 sharedSession 类方法创建会话对象,因为需要根据请求对会话对象进行配置。在viewDidLoad 方法中:

- (void)viewDidLoad {
    [super viewDidLoad];
 
    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:[NSURL URLWithString:@"http://cdn.tutsplus.com/mobile/uploads/2013/12/sample.jpg"]];
    [downloadTask resume];
}

译者注:由于代码中的图片链接地址有可能打不开(测试时,出现过),所以读者需要先将链接地址到浏览器中测试能否打开,若不能,则随便替换一个图片链接地址。译者就是无法打开该链接的图片,所以替换为这个链接:http://iphone.images.paojiao.cn//iphone/paper/201111/4/97108898/paojiao_08a86f17_280x420.jpg

To prevent any compiler warning from popping up, make sure to conform theMTViewController class to the NSURLSessionDelegate and NSURLSessionDownloadDelegateprotocols as shown below.

为了避免出现编译错误,确保 MTViewController 类遵循 NSURLSessionDelegate  和 NSURLSessionDownloadDelegate 协议。

#import "MTViewController.h"
 
@interface MTViewController() <NSURLSessionDelegate, NSURLSessionDownloadDelegate>
 
@end

In viewDidLoad, we create an instance of the NSURLSessionConfiguration class by invoking the defaultSessionConfiguration class method. As stated in the documentation, by using the default session configuration the session will behave much like an instance of NSURLConnection in its default configuration, which is fine for our example.

在 viewDidLoad 方法中,我们通过调用  defaultSessionConfiguration  类方法创建 NSURLSessionConfiguration 类的实例。使用默认的会话配置将会使会话的行为和 NSURLConnection 实例的默认配置类似。

In this example, we create a NSURLSession instance by invoking thesessionWithConfiguration:delegate:delegateQueue: class method and pass thesessionConfiguration object we created a moment ago. We set the view controller as the session delegate and pass nil as the third argument. You can ignore the third argument for now. The main difference with the previous example is that we set thesession's delegate to the view controller.

在这个例子中,我们创建创建 NSURLSession 实例是通过调用 sessionWithConfiguration:delegate:delegateQueue: 类方法,然后传入 sessionConfiguration 对象作为参数进行创建。我们设置视图控制器为会话的委托对象,然后传递 nil 给第三个参数。你可以暂时忽略第三个参数的含义。这和之前例子最主要的不同是我们设置 session 的委托对象为视图控制器。

To download the image, we need to create a download task. We do this by callingdownloadTaskWithURL: on the session object, passing an instance of NSURL, and callingresume on the download task. We could have made use of a completion handler like we did earlier, but I want to show you the possibilities of using a delegate instead.

为了下载图像,我们要创建一个 Download 任务。我们在 session 会话对象上调用 downloadTaskWithURL: 方法,传入一个 NSURL 实例,在调用 resume 方法去开始下载任务。我们这里可以使用完成程序代码块处理接收请求响应,但是我这里想要使用委托方法进行实现。

Step 3: Implement the Delegate Protocol

To make all this work, we need to implement the three delegate methods of theNSURLSessionDownloadDelegate protocol,URLSession:downloadTask:didFinishDownloadingToURL:,

URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:, andURLSession:downloadTask:downloadTask didWriteData:totalBytesWritten:totalBytesExpectedToWrite:. The implementation of each method is quite easy. It's important to note that we need update the user interface on the main thread using GCD (Grand Central Dispatch). By passing nil as the third argument of sessionWithConfiguration:delegate:delegateQueue:, the operating system created a background queue for us. This is fine, but it also means that we need to be aware that the delegate methods are invoked on a background thread instead of the main thread. Build the project and run the application to see the result of our hard work.

为了完成下载过程,我们需要实现 NSURLSessionDownloadDelegate  委托协议的如下三个方法:URLSession:downloadTask:didFinishDownloadingToURL:  ,URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:  和 didWriteData:totalBytesWritten:totalBytesExpectedToWrite: 。每一个委托方法的实现都比较简单。重点需要注意的是要使用 GCD(Grand Central Dispatch) 在主线程中更新用户界面(UI)。由于在 sessionWithConfiguration:delegate:delegateQueue: 方法中传入 nil 作为其第三个参数,操作系统自动为我们创建一个后台队列。在本例中是适用的,同时我们也要意识到这些委托方法是在后台线程中进行调用执行的,而非在主程序中。编译运行项目程序,观察结果。

- (void)URLSession:(NSURLSession*)session downloadTask:(NSURLSessionDownloadTask*)downloadTask didFinishDownloadingToURL:(NSURL*)location {
    NSData *data = [NSData dataWithContentsOfURL:location];
 
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.progressView setHidden:YES];
        [self.imageView setImage:[UIImage imageWithData:data]];
    });
}
 
- (void)URLSession:(NSURLSession*)session downloadTask:(NSURLSessionDownloadTask*)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {
 
}
 
- (void)URLSession:(NSURLSession*)session downloadTask:(NSURLSessionDownloadTask*)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
    float progress = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
 
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.progressView setProgress:progress];
    });
}


译者注:运行项目其结果:进度条显示图像下载进度(从0开始),下载完毕,进度条隐藏,图像显示。

Conclusion

With these two examples, you should have a basic understanding of the fundamentals of the NSURLSession API, how it compares to NSURLConnection, and what its advantages are. In the next part of this series, we will look at more advanced features ofNSURLSession.

有了这两个例子,你应该对 NSURLSession 的基础知识,它和 NSURLConnection 的比较,它的优势有了一定的了解。在下一篇教程中,我们将深入了解 NSURLSession 的其它先进特性。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值