Research Group for Applied Software Engineering
Forschungsgruppe für Angewandte Softwaretechnik

“Tell me and I will forget.

Show me and I will remember.

Involve me and I will understand.

Step back and I will act.”

 

iOS Client Server Communication Tutorial

 

Table of Contents

1. Introduction
1.1 What is client-server communication?
1.2 When is client-server communication used?
2. REST
2.1 What is RESTful Communication?
2.2 RESTful CRUD operations
3. NSURLSession
3.1 Class Overview
3.2 NSURLSessionConfiguration
3.3 NSURLSessions
3.4 NSURLSessionTasks
4. AFNetworking
4.1 What is AFNetworking?
4.2 What are the most popular usages of AFNetworking?
4.3 Architecture
4.5 Integrating AFNetworking
4.6 RESTful methods implemented with AFNetworking
4.7 NSURLSessionDataTask using AFNetworking
4.7.1 How to use UIImageView+AFNetworking?
4.8 UIKit Extensions
5. Hands on tutorial
Summary
References

 

1. Introduction 

1.1 What is client-server communication?

In client-server communication we have first of all two obvious partners: The client and the server. Normally we think about multiple clients and one “central” server (normally, because the server side can also be scaled with multiple servers, but that’s not interesting for us.

 

Client Server Communication 02

To understand the communication between these two partners, we need to know some simple topics:

  • Requests: Requests are sent from the client in order to ask the server for some data like files, or tell the server about things that happen, like that a user wants to login with his credentials
  • Response: A response is sent from the server to the client and is the reaction of the server to a request of the client. This could for example be an authentication result.
  • Service: A Service is a specific task that the server provides for the client to use, like downloading imageClient Server Communication 01

 

 

1.2 When is client-server communication used?

Client-Server communication is always used, whenever someone requests something from the internet. Some examples would be applications like Facebook, Twitter, Instagram, Maps or even simple games like Temple Run and so on.

 

2. REST

2.1 What is RESTful Communication?

RESTful communication means implementation of a web service using HTTP and REST principles.

REST Principles are:

- Application state and functionality are divided into resources and than the application would respond based on the resource that the operation is being performed

- Resources are addressable using standard URIs that can be used as hypermedia links such as  http://example.com/resources/  and than for each resource the type of the resource is added in the URI such as  http://example.com/resources/resource.

- Resources provide information using MIME types supported by HTTP (e.g JSON, XML, Atom, etc.)

- Use only standard HTTP methods which are GET, PUT, POST and DELETE.

- Protocol is stateless, cacheable and layered

Stateless which means that the server would not need to remember any kind of information regarding the state of the client whereas the client would need to include all the information in its request. REST allows caching which means that the responses would need to be defined as cacheable which would eliminate some client-server interaction, further improving scalability and performance. Layered meaning that the client does not know if the server that is responding is the actually the end server that is serving the resource which is a great principle to enable load balancing and provide shared caches.

 

2.2 RESTful CRUD operations

In RESTful architecture, CRUD operations correspond to basic HTTP methods. Create is being implemented using POST method, Read using GET method, Update using PUT method and DELETE using DELETE method.

 

As a summary, the advantages of REST web service are performance, scalability, simplicity, portability of component deployment and reliability.

 

3. NSURLSession

3.1 Class Overview

At first lets look at the basic classes that we get with NSURLSession:

Client Server Communication 00

The three main parts here are the NSURLSession, the NSURLSessionDelegate and the NSURLSessionTask. In order to communicate with a server we need a NSURLSession object as our basis, which we can create using a NSURLSessionConfiguration. With this NSURLSession obect we can then create multiple NSURLSessionTask, like download or upload tasks, which decide the way we send information to the server and handle information from the server.

3.2 NSURLSessionConfiguration

With NSURLSessionConfiguration we get three different predefined configurations to choose from: backgroundSessionConfiguration, defaultSessionConfiguration and backgroundSessionConfiguration. Lets look at these and see where they store all the informations about the connection to the server :

Client Server Communication 03

Here are some code exapmles of how we could create a configuration object using one of these predefined configurations:

 
NSURLSessionConfiguration *defaultConfig =
[NSURLSessionConfiguration defaultSessionConfiguration];

NSURLSessionConfiguration *ephemeralConfig =
[NSURLSessionConfiguration ephemeralSessionConfiguration];

NSURLSessionConfiguration *backgroundConfig =
[NSURLSessionConfiguration backgroundSessionConfiguration: @"myBackgroundSessionIdentifier"];
 

3.3 NSURLSessions

We are now ready to create oureselves a NSURLSession object using the one of the just created configurations:

NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfig];

 

3.4 NSURLSessionTasks

Once we create a NSURLSession object using one of the configurations we talked about earlier, we can go ahead and create us some NSURLSessionDataTasks. Keep in mind that you can reuse on NSURLSession object to create more tasks. As you can see in the UML model above, we have three tasks to choose from:

table of tasks with corresponding functions and delegates

Client Server Communication 03

 
Code Example:
NSURLSessionDataTask *dataTask =
   [_session dataTaskWithURL:url
           completionHandler:^(NSData *data,
                               NSURLResponse *response,
                               NSError *error) {
               if (!error) {
                   NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
                   NSLog(@"response: %@",httpResp);
                   if (httpResp.statusCode == 200) {
// handle the response here
                   }
               }
           }
    ];
 
 

4. AFNetworking

AFNetworking

4.1 What is AFNetworking?

AFNetworking is one of the most widely used open-source objective-c third party library which is an alternative to using NSURLSession. The latest version of AFNetworking is the second version which is built on top of NSURLSession which means that it leverages all the great features introduced in NSURLSession API combined with extra cool features on top of it such as communication management, serialization, reachability support, UIKit extensions and more.

In this part of the tutorial, we are going to explain the most popular use cases of AFNetworking and how easy is to implement them on your project.

 

4.2 What are the most popular usages of AFNetworking?

Communication Management is far easier using AFNetworking as AFHTTPRequestOperationManager encapsulates the common patterns of communication over HTTP by creating the requests, serializing the responses, managing security, monitoring networking reachability as well as request operation management (which means that the request operation can be started, paused, continued or stopped). AFURLSessionManager allows easy creation and management of NSURLSession based on a specific configuration. Serialization module of AFNetworking makes it very easy to serialize a request before executing it by encoding the parameters that need to be included in that request and also helps decoding the response to a specified type.

 

4.3 Architecture

**UML class diagram image**

 

4.4 Integrating AFNetworking

The developer can easily integrate AFNetworking by either using Cocoapods which does (cross) dependency resolution, (semantic) version management, and automating the ‘integrating it into Xcode’ parts or integrate the latest version manually by:

1. Downloading the AFNetworking library at AFNetworking Official Website

2. Include AFNetworking and UIKit+AFNetworking folders in your project by drag and dropping

3. Import AFNetworking header file (AFNetworking.h)in the class that you are using it

#import "AFNetworking.h"

 

4.5 RESTful methods implemented with AFNetworking

Implementing communication requests to a RESTful web service using AFNetworking is relatively easy.

What you would need to do is:

1. Create a NSURL from the domain of the url which is used as the base url for the communication

2. Create a AFHTTPSessionManager object with the base url and set its response serializer object to a JSON serializer

3. If the communication method needed for this request is GET than you call the GET method passing the resource part of the URI and parameters of the request (pretty similar for POST, PUT and DELETE methods)

4. Implement the success and failure blocks

GET 
 
NSURL *baseURL = [NSURL URLWithString:@"http://example.com/"];
NSDictionary *parameters = @{@"format": @"json"};

AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:baseURL];
manager.responseSerializer = [AFJSONResponseSerializer serializer];

[manager GET
:@"resources.json" parameters:nil success:^(NSURLSessionDataTask *operation, id responseObject) {

   NSLog(
@"JSON: %@", responseObject);
} failure
:^(NSURLSessionDataTask *operation, NSError *error) {

   NSLog(
@"Error: %@", error);
}];
 

4.6 NSURLSessionDataTask using AFNetworking

In case when there is a need for DataTask, UploadTask or DownloadTask AFURLSessionManager can be used.

Steps to implement a data task are:

1. Create a NSURLSessionConfiguration based using one of the configurations such as default, ephemeral or background.

2. Create an AFURLSessionManager using the created configuration above

3. Create a NSURL and based on that create a NSURLRequest

4. Create a NSURLSessionDataTask by calling the manager's method dataTaskWithRequest:request completionHandler:

5. Call the resume method on that data task to execute the request

Example code:

 
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 

AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];  

NSURL *URL = [NSURL URLWithString:@"http://example.com/upload"];

NSURLRequest *request = [NSURLRequest requestWithURL:URL];  

NSURLSessionDataTask *dataTask =
[manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {         
if (error) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"Success: %@ %@", response, responseObject);
} }];
[dataTask resume];
 

4.7 UIKit Extensions

In AFNetworking, there are a few extensions of native UIControls such as:

- UIActivityIndicatorView+AFNetworking

- UIAlertView+AFNetworking

- UIButton+AFNetworking

- UIImageView+AFNetworking

- UIProgressView+AFNetworking

- UIRefreshControl+AFNetworking

- UIWebView+AFNetworking

 These extensions help you tieing specific networking events to the controls mostly when a network state changes such as the request started, finished, failed but also making asynchronous requests easier.

4.7.1 How to use UIImageView+AFNetworking?

An example of using UIImageView+AFNetworking is in case that we want to asynchronously load an image from a URL to an UIImageView. Using AFNetworking we can easily implement this feature by:

- Importing the UIImageView+AFNetworking header file on the class that we are currently working on

- Create a request based on a NSURL which points out to the image URL 

NSURL *url = [NSURL URLWithString: @"http://image_url.com"];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL: url];
 
 
- (optional) Instantiate a UIImage with a local image that will be used until the image from the url is downloaded
 
UIImage *placeholderImage = [UIImage imageNamed:@”placeHolderImage”];

 

- On the UIImageView that we would like to display the downloaded image we call the AFNetworking extension method

setImageWithURLRequest:placeholderImage:success:failure:

 

[imageView setImageWithURLRequest:request placeholderImage:placeholderImage 
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {

        // If you don’t provide a success block (success:nil), the image will automatically be set for you.
 } failure:nil];
 

5. Hands on tutorial

As we explained most of the crucial concepts and principles of client-server communications and features of NSURLSession and AFNetworking, its time to get hands on a tutorial where the usage can be seen in a real example.

During this practical part of the tutorial we will implement:

- Simple implementation of UIImageView by synchronously downloading an image based on a URL

- Filling a table view using NSURLSessionDataTask with native APIs

- Implementing a GET request using AFNetworking

- Advanced implementation of UIImageView by asynchronously downloading an image based on a URL

 

1. Start by downloading the initial project here.

2. Build the project and you will see the warnings about the given tasks

 

Let's start with the first task

1. Create a UIImage from the given URL(there is a constant called imgUrl that contains the url of the image that you can use to download):

UIImage *image = [UIImageimageWithData:[NSDatadataWithContentsOfURL:[NSURLURLWithString:imgUrl]]];

2. Create a UIImageView from the created UIImage:

UIImageView *myImageView = [[UIImageView alloc] initWithImage:image];

3. Create a CGRect to be used as the frame of the image view, set it to the image view, change the content mode to scale aspect fit and add the image view to the view of the view controller. 

    CGRect frame;
    frame.size.width = [[UIScreenmainScreen] bounds].size.width;
    frame.size.height = [[UIScreenmainScreen] bounds].size.height;
    myImageView.frame = frame;
    myImageView.contentMode = UIViewContentModeScaleAspectFit;
    [self.view addSubview:myImageView];

4. Build and run the project to see if everything is working as expected :)

5. **screenshot from the app**

 

Let's continue with the second task

1. Create a default configuration object

NSURLSessionConfiguration *config = [NSURLSessionConfigurationdefaultSessionConfiguration];

2. Create a session with the just created config and assign it to the property _session 

_session = [NSURLSession sessionWithConfiguration:config];

3. Create a NSURL with the constant variable apiString

NSURL *url = [NSURL URLWithString: apiString];

4. Create a NSURLSessionDataTask with a completionHandler

 

// 1
NSURLSessionDataTask *dataTask =
[_sessiondataTaskWithURL:url
                completionHandler:^(NSData *data,
                                    NSURLResponse *response,
                                    NSError *error) { // 2
                    if (!error) {
                        NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
                        NSLog(@"response: %@",httpResp);
                        // 2.1
                        if (httpResp.statusCode == 200) {
                            
                            NSError *jsonError;
                            // 2.2
                            NSDictionary *notesJSON =
                            [NSJSONSerialization JSONObjectWithData:data
                                                            options:NSJSONReadingAllowFragments
                                                              error:&jsonError];
                            // 2.3
                            if (!jsonError) {
                                NSLog(@"noteJson: %@", notesJSON);
                                // 2.4
                                [_myData removeAllObjects];
                                for(NSDictionary *loan in notesJSON[@"loans"]){
                                    [_myData addObject:loan[@"name"]];
                                }
                                //[_myData addObject:notesJSON[@"md5"]];
                                // 2.5
                                dispatch_async(dispatch_get_main_queue(), ^{
                                    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
                                    [self.tableView reloadData];
                                    [self.refreshControl endRefreshing];
                                });
                            }else{
                                NSLog(@"json error: %@", jsonError);
                            }
                        }
                    }                
                }];
 


  

What we are doing here is:

1. We are calling the dataTaskWithURL:completionHandler: method on the member variable _session and saving that to a local variable NSURLSessionDataTask.

2. We are implementing the completionHandler

2.1 We are checking if the response has returned a status code of 200 which means that everything regarding the request went right

2.2 By using the NSJSONSerialization we are decoding the response data as JSON into a NSDictionary

2.3 If the json has been fetched without any error than we continue

2.4 We are removing all the elements from the table view of the current view controller, adding the names of the loans from the fetched json (in NSDictionary now) and

2.5 Removing the loading indicators and refreshing the table view

 

5. Build and run the application to see if everything is working correctly

6. **screenshot from the app**

 

Let's continue with the third task

1. Create a NSURL with the constant variable apiString

NSURL *url = [NSURL URLWithStringapiString];

2. Create an AFHTTPSessionManager using the created url and set its response serializer to a JSON serializer

    AFHTTPSessionManager *manager = [[AFHTTPSessionManageralloc] initWithBaseURL:url];
    manager.responseSerializer = [AFJSONResponseSerializerserializer];

3. Call the get method (GET:parameters:success:failure:) on the manager 

 

    [manager GET:@"teams/search.json" parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        // update the UI with new GET data
        // the responseObject is a NSDictionary object prased from the response (json format)
        NSLog(@"%@", responseObject);
        // Remove all the objects from the array being used by the table view
        [_myDataremoveAllObjects];
        // Add new objects containing the "shortname" field of "teams" from responseObject
        for(NSDictionary *loan in responseObject[@"teams"]){
            [_myData addObject:loan[@"whereabouts"]];
        }
        NSLog(@"%d", [_myData count]);
        // Remove the network activity indicator, reload the table view and end the refresh control
        dispatch_async(dispatch_get_main_queue(), ^{
            [UIApplicationsharedApplication].networkActivityIndicatorVisible = NO;
            [self.tableView reloadData];
            [self.refreshControl endRefreshing];
        });
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        // inform the user for failure
    }];
 

 

What we are doing here is:

1. We are calling the GET:parameters:success:failure: method on the manager

2. We are implementing the success block

2.1 In this case the response serializer will handle all the json decoding stuff that we did on the previous example

2.2 We are removing all the elements from the table view of the current view controller, adding the whereabouts of the teams from the fetched json (ready in responseObject now) and

2.5 Removing the loading indicators and refreshing the table view

 

4. Build and run the application to see if everything is working correctly

5. **screenshot from the app**

 

Let's continue with the forth task

1. Import the AFNetworking extension of UIImageView

#import "UIImageView+AFNetworking.h"

2. Create an UIImage from the placeholder image already included in the project and set it as an image of the UIImageView in instantiation

 
    UIImage *placeholderImage = [UIImage imageNamed:@"placeholder"];
    UIImageView *myImageView = [[UIImageView alloc] initWithImage:placeholderImage];
 

3. Call the method setImageWithURLRequest:placeholderImage:success:failure: on the UIImageView (pay attention that this method is a method defined in the extension of the AFNetworking and not on the native implementation of the UIImageView in iOS SDK)

 
    [myImageView setImageWithURLRequest:request
                          placeholderImage:placeholderImage
                                   success:nil failure:nil];
 
 

4. Build and run the application to see if everything is working correctly

5. Observe the difference between asynchronous and synchronous implementation of the UIImageView

5. **screenshot from the app**

 

Summary

- There are several ways to communicate with a server

- NSURLSession is the new, preferred method of networking (as opposed to the older NSURLConnection API)

- An alternative to NSURLSession is the popular third-party library AFNetworking

- AFNetworking helps us with communication management, serialization, reachability, security and UIKit integration

 

References

AFNetworking Official Documentation http://cocoadocs.org/docsets/AFNetworking/2.0.0/
NSURLSession Official Documentation https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSession_class/Introduction/Introduction.html
NSURLSession Tutorial http://www.raywenderlich.com/51127/nsurlsession-tutorial
REST Wikipedia http://en.wikipedia.org/wiki/Representational_state_transfer
AFNetworking Tutorial http://www.raywenderlich.com/30445/afnetworking-crash-course
NSURLConnection to NSURLSession Article http://www.objc.io/issue-5/from-nsurlconnection-to-nsurlsession.html
WWDC NSURLSession Session http://asciiwwdc.com/2013/sessions/705