In the previous installments of this series, we've taken a close look at the NSURLSession
API introduced in iOS 7 and OS X Mavericks. Networking on iOS and OS X has become much simpler and more flexible thanks to the NSURLSession
API. Does this mean that you should stop using AFNetworking for your networking needs? And what about AFNetworking 2.0, which was introduced a few months ago? In this final installment, I will tell you about AFNetworking 2.0 and how it compares to the NSURLSession
API.
Introduction
As Mattt Thompson points out on NSHipster, AFNetworking has become the de facto networking library for Cocoa applications. At the time of writing, the library has surpassed 10,000 stars on GitHub and was forked close to 3,000 times.
If you're new to AFNetworking and would like to read more about its history and features, then I suggest to read Mattt's post about AFNetworking 2.0 on NSHipster. In this article, I'd like to focus on two aspects, what is new in AFNetworking 2.0 and how does it compare to the NSURLSession
API . The question you should be asking yourself is "Should I still be using AFNetworking with NSURLSession
in my toolbox?" That's the question I plan to answer in this article.
Requirements
Before we take a closer look at what AFNetworking 2.0 has to offer, it's important to know about the library's new requirements. It shouldn't be a surprise that the requirements of AFNetworking 2.0 are stricter than those of AFNetworking 1.x. As its version number indicates, AFNetworking includes breaking changes, which are the result of its new architecture. This also means that migrating a project from AFNetworking 1.x to 2.0 should be done with caution. The migration guide is the ideal place to start if you plan on migrating a project to AFNetworking 2.0.
AFNetworking no longer supports iOS 4.3 and 5. The minimum deployment targets for iOS and OS X are iOS 6 and OS X 10.8 respectively. AFNetworking 2.0 also requires Xcode 5. If you're still using Xcode 4, this may be a good time to make the transition to Xcode 5.
Solid Foundation
AFURLConnectionOperation
As many of you probably know, AFNetworking is built on top of NSURLConnection
and NSOperation
, which has proven to be a powerful and elegant combination. The result of this combination is AFURLConnectionOperation
, an NSOperation
subclass that manages an NSURLConnection
instance and implements the NSURLConnectionDelegate
protocol. Even though this robust foundation remains unchanged in AFNetworking 2.0, it is supplemented by the NSURLSession
API, which I'll cover in more detail later.
Separation of Responsibilities
In AFNetworking 1.x, the AFHTTPRequestOperation
class was in charge of request and response serialization and validation. This is no longer true in AFNetworking 2.0. The AFHTTPRequestOperation
class and its subclasses are no longer directly responsible for serializing and validating requests and responses. This responsibility has been moved to the AFURLRequestSerialization
and AFURLResponseSerialization
protocols. Each protocol declares a single delegate method to handle request and response serialization and validation respectively.
To make your life easier, however, AFNetworking 2.0 ships with AFHTTPRequestSerializer
and AFHTTPResponseSerializer
as well as a number of subclasses for common content types, such as JSON and XML. To see how this works in practice, let's take a look at an example in which I query the Forecast API. This doesn't look all that different from how you made a request with AFNetworking 1.x. The main difference is that you'll be using the AFHTTPRequestOperation
class more often. The AFJSONRequestOperation
and AFXMLRequestOperation
classes are no longer present in AFNetworking 2.0.
NSString *key = @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"https://api.forecast.io/forecast/%@/37.8267,-122.423", key]]; // Initialize Request Operation AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequest requestWithURL:URL]]; // Configure Request Operation [requestOperation setResponseSerializer:[AFJSONResponseSerializer serializer]]; [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { // Process Response Object } failure:^(AFHTTPRequestOperation *operation, NSError *error) { // Handle Error }]; // Start Request Operation [requestOperation start];
The AFJSONResponseSerializer
class inherits from AFHTTPResponseSerializer
and should be used for JSON responses. If you need to process XML responses, then AFXMLNResponseSerializer
will help you out. For other content types, you need to subclass AFHTTPResponseSerializer
.
AFHTTPRequestOperationManager
Another major change in AFNetworking 2.0 is the removal of the AFHTTPClient
class, which was in charge of talking to web services. The responsibilities of AFHTTPClient
have been split up into a number of classes and protocols. To talk to a web service, you now use AFHTTPRequestOperationManager
and AFHTTPSessionManager
. Just like AFHTTPRequestOperation
, AFHTTPRequestOperationManager
and AFHTTPSessionManager
delegate serialization of requests and responses to separate objects. Both AFHTTPRequestOperationManager
and AFHTTPSessionManager
have a requestSerializer
and responseSerializer
property for this purpose. Let's revisit the above example to see how this works in practice.
NSString *key = @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; NSURL *baseURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://api.forecast.io/forecast/%@/", key]]; // Initialize Request Operation Manager AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:baseURL]; // Configure Request Operation Manager [manager setResponseSerializer:[AFJSONResponseSerializer serializer]]; // Send Request [manager GET:@"37.8267,-122.423" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { // Process Response Object } failure:^(AFHTTPRequestOperation *operation, NSError *error) { // Handle Error }];
What About NSURLSession
?
AFURLSessionManager
The key question when discussing AFNetworking 2.0 in the light of the NSURLSession
API is whether we still need AFNetworking. AFNetworking adds a number of convenience classes and methods to the NSURLSession
API and this is only possible thanks to the separation of responsibilities I discussed earlier. The most significant improvement that AFNetworking provides on top of the NSURLSession
API are the AFURLSessionManager
and AFHTTPSessionManager
classes.
The AFURLSessionManager
helps you manage an NSURLSession
object. Even though I love the NSURLSession
API, I have to agree with Mattt that its API is incomplete. The AFURLSessionManager
class adds a number of convenience methods that make the NSURLSession
API even better. Serialization and validation, for example, are much easier and intuitive with AFNetworking. Just like the AFHTTPRequestOperationManager
, instances of AFURLSessionManager
have a requestSerializer
and responseSerializer
property that makes serialization of requests and responses seamless and intuitive.
NSString *key = @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"https://api.forecast.io/forecast/%@/37.8267,-122.423", key]]; // Initialize Session Configuration NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; // Initialize Session Manager AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:sessionConfiguration]; // Configure Manager [manager setResponseSerializer:[AFJSONResponseSerializer serializer]]; // Send Request NSURLRequest *request = [NSURLRequest requestWithURL:URL]; [[manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { // Process Response Object }] resume];
I hope you can see the benefit of using AFNetworking in combination with the NSURLSession
API. It makes working with the NSURLSession
API much more intuitive especially if you're already used to the way AFNetworking 2.0 separates serialization and validation from the actual task or request operation.
AFHTTPSessionManager
AFNetworking 2.0 also incudes a subclass of AFURLSessionManager
, AFHTTPSessionManager
, which makes interacting with web services a breeze. The AFHTTPSessionManager
class includes a number of conveniences methods, such as GET:parameters:success:failure:
and POST:parameters:constructingBodyWithBlock:success:failure:
that make the migration process from AFHTTPClient
to AFHTTPSessionManager
easy. Similar methods are also available in the AFHTTPRequestOperationManager
class, which I discussed earlier.
Reachability
Reachability is managed by the AFURLRequestOperationManager
and AFURLSessionManager
classes. When instances of these classes have a valid baseURL
, then a reachability manager is automatically instantiated and set up. Of course, it is also possible to explicitly create an instance of the AFNetworkReachabilityManager
class.
Icing On The Cake
AFNetworking 2.0 has a number of other features, such as built-in support for SSL pinning and various categories on UIKit classes. Take a look at this example in which I leverage AFNetworking's category on UIProgressView
to update a progress view while downloading a remote image.
// Initialize Request NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://cdn.tutsplus.com/mobile/uploads/2014/01/5a3f1-sample.jpg"]]; // Initialize Session Manager self.sessionManager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; // Initialize Download Task NSURLSessionDownloadTask *downloadTask = [self.sessionManager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) { // Handle Success } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) { // Handle Failure }]; [self.progressView setProgressWithDownloadProgressOfTask:downloadTask animated:YES]; [downloadTask resume];
Verdict
If your project doesn't rely on networking, then you won't need all the power and convenience that AFNetworking has to offer. As a matter of fact, I think it's important that every iOS or OS X developer is familiar with NSURLSession
and NSURLConnection
, because they are key components of the platform.
Even though the NSURLSession
API is great and easy to use, the networking APIs provided by the Foundation framework aren't perfect. As Mattt points out, even the NSURLSession
API has a few notable gaps. AFNetworking tries to elegantly fill these gaps. The combination of the NSURLSession
API and AFNetworking is a marriage made in heaven. It truly is a joy to use.
I really like the NSURLSession
API and I hope I've convinced you of its power in this series. However, this doesn't mean that AFNetworking has become obsolete. In my opinion, AFNetworking is the perfect companion of the NSURLSession
API. AFNetworking has matured and it is indeed the best and most robust networking library available. Its modular architecture means that you don't need to include every class or category it has to offer. You are free to pick and choose from the components that it includes. AFNetworking supports CocoaPods subspecs, which make this process trivial.
Conclusion
I couldn't be more happy with the second major release of AFNetworking. The library's modularity and separation of responsibilities is what makes it shine in my opinion. It complements the NSURLSession
API so well that you won't even notice that you're using AFNetworking. Mattt Thompson and the more than 130 contributors of AFNetworking have done a formidable job. It's good to be a Cocoa developer.
Comments