AFNetworking 2.0 Tutorial
Learn how to easily get and post data from a web service in iOS in this AFNetworking 2.0 tutorial. By Joshua Greene.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Update 1/18/2014: Fully updated for iOS 7 and AFNetworking 2.0 (original post by Scott Sherwood, update by Joshua Greene).
In iOS 7, Apple introduced NSURLSession as the new, preferred method of networking (as opposed to the older NSURLConnection API). Using this raw NSURLSession API is definitely a valid way to write your networking code – we even have a tutorial on that.
However, there’s an alternative to consider – using the popular third party networking library AFNetworking.
The latest version of AFNetworking (2.0) is now built on top of NSURLSession, so you get all of the great features provided there. But you also get a lot of extra cool features – like serialization, reachability support, UIKit integration (such as a handy category on asynchronously loading images in a UIImageView), and more.
AFNetworking is incredibly popular – it won our Reader’s Choice 2012 Best iOS Library Award. It’s also one of the most widely used, open-source projects with over 10,000 stars, 2,600 forks, and 160 contributors on Github.
In this AFNetworking 2.0 tutorial, you will learn about the major components of AFNetworking by building a Weather App that uses feeds from World Weather Online. You’ll start with static weather data, but by the end of the tutorial, the app will be fully connected to live weather feeds.
Today’s forecast: a cool developer learns all about AFNetworking and gets inspired to use it in his/her apps. Let’s get busy!
Getting Started
First download the starter project for this AFNetworking 2.0 tutorial here.
This project provides a basic UI to get you started – no AFNetworking code has been added yet.
Open MainStoryboard.storyboard, and you will see three view controllers:
From left to right, they are:
- A top-level navigation controller
- A table view controller that will display the weather, one row per day
- A custom view controller (WeatherAnimationViewController) that will show the weather for a single day when the user taps on a table view cell
Build and run the project. You’ll see the UI appear, but nothing works yet. That’s because the app needs to get its data from the network, but this code hasn’t been added yet. This is what you will be doing in this tutorial!
The first thing you need to do is include the AFNetworking framework in your project. Download the latest version from GitHub by clicking on the Download Zip link.
When you unzip the file, you will see that it includes several subfolders and items. Of particular interest, it includes a subfolder called AFNetworking and another called UIKit+AFNetworking as shown below:
Drag these folders into your Xcode project.
When presented with options for adding the folders, make sure that Copy items into destination group’s folder (if needed) and Create groups for any added folders are both checked.
To complete the setup, open the pre-compiled header Weather-Prefix.pch from the Supporting Files section of the project. Add this line after the other imports:
#import "AFNetworking.h"
Adding AFNetworking to the pre-compiled header means that the framework will be automatically included in all the project’s source files.
Pretty easy, eh? Now you’re ready to “weather” the code!
Operation JSON
AFNetworking is smart enough to load and process structured data over the network, as well as plain old HTTP requests. In particular, it supports JSON, XML and Property Lists (plists).
You could download some JSON and then run it through a parser (like the built-in NSJSONSerialization) yourself, but why bother? AFNetworking can do it all!
First you need the base URL of the test script. Add this to the top of WTTableViewController.m, just underneath all the #import lines.
static NSString * const BaseURLString = @"http://www.raywenderlich.com/demos/weather_sample/";
This is the URL to an incredibly simple “web service” that I created for you for this tutorial. If you’re curious what it looks like, you can download the source.
The web service returns weather data in three different formats – JSON, XML, and PLIST. You can take a look at the data it can return by using these URLS:
- http://www.raywenderlich.com/demos/weather_sample/weather.php?format=json
- http://www.raywenderlich.com/demos/weather_sample/weather.php?format=xml
- http://www.raywenderlich.com/demos/weather_sample/weather.php?format=plist (might not show correctly in your browser)
The first data format you will be using is JSON. JSON is a very common JavaScript-derived object format. It looks something like this:
{
"data": {
"current_condition": [
{
"cloudcover": "16",
"humidity": "59",
"observation_time": "09:09 PM",
}
]
}
}
Note: If you’d like to learn more about JSON, check out our Working with JSON Tutorial.
Note: If you’d like to learn more about JSON, check out our Working with JSON Tutorial.
When the user taps the JSON button, the app will load and process JSON data from the server. In WTTableViewController.m, find the jsonTapped: method (it should be empty) and replace it with the following:
- (IBAction)jsonTapped:(id)sender
{
// 1
NSString *string = [NSString stringWithFormat:@"%@weather.php?format=json", BaseURLString];
NSURL *url = [NSURL URLWithString:string];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 2
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// 3
self.weather = (NSDictionary *)responseObject;
self.title = @"JSON Retrieved";
[self.tableView reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// 4
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error Retrieving Weather"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
[alertView show];
}];
// 5
[operation start];
}
Awesome, this is your first AFNetworking code! Since this is all new, I’ll explain it one section at a time.
- You first create a string representing the full url from the base URL string. This is then used to create an NSURL object, which is used to make an NSURLRequest.
- AFHTTPRequestOperation is an all-in-one class for handling HTTP transfers across the network. You tell it that the response should be read as JSON by setting the responseSerializer property to the default JSON serializer. AFNetworking will then take care of parsing the JSON for you.
- The success block runs when (surprise!) the request succeeds. The JSON serializer parses the received data and returns a dictionary in the responseObject variable, which is stored in the weather property.
- The failure block runs if something goes wrong – such as if networking isn’t available. If this happens, you simply display an alert with the error message.
- You must explicitly tell the operation to “start” (or else nothing will happen).
As you can see, AFNetworking is extremely simple to use. In just a few lines of code, you were able to create a networking operation that both downloads and parses its response.
Now that the weather data is stored in self.weather, you need to display it. Find the tableView:numberOfRowsInSection: method and replace it with the following:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(!self.weather)
return 0;
switch (section) {
case 0: {
return 1;
}
case 1: {
NSArray *upcomingWeather = [self.weather upcomingWeather];
return [upcomingWeather count];
}
default:
return 0;
}
}
The table view will have two sections: the first to display the current weather and the second to display the upcoming weather.
“Wait a minute!”, you might be thinking. What is this [self.weather upcomingWeather]? If self.weather is a plain old NSDictionary, how does it know what “upcomingWeather” is?
To make it easier to display the data, I added a couple of helper categories on NSDictionary in the starter project:
- NSDictionary+weather
- NSDictionary+weather_package
These categories add some handy methods that make it a little easier to access the data elements. You want to focus on the networking part and not on navigating NSDictionary keys, right?
Note: FYI, an alternative way to make working with JSON results a bit easier than looking up keys in dictionaries or creating special categories like this is to use a third party library like JSONModel.
Note: FYI, an alternative way to make working with JSON results a bit easier than looking up keys in dictionaries or creating special categories like this is to use a third party library like JSONModel.
Still in WTTableViewController.m, find the tableView:cellForRowAtIndexPath: method and replace it with the following implementation:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"WeatherCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSDictionary *daysWeather = nil;
switch (indexPath.section) {
case 0: {
daysWeather = [self.weather currentCondition];
break;
}
case 1: {
NSArray *upcomingWeather = [self.weather upcomingWeather];
daysWeather = upcomingWeather[indexPath.row];
break;
}
default:
break;
}
cell.textLabel.text = [daysWeather weatherDescription];
// You will add code here later to customize the cell, but it's good for now.
return cell;
}
Like the tableView:numberOfRowsInSection: method, the handy NSDictionary categories are used to easily access the data. The current day’s weather is a dictionary, and the upcoming days are stored in an array.
Build and run your project; tap on the JSON button to get the networking request in motion; and you should see this:
JSON success!