How To Create an App Like Instagram With a Web Service Backend – Part 1/2

This is a blog post by iOS Tutorial Team member Marin Todorov, a software developer with 12+ years of experience, an independent iOS developer and the creator of Touch Code Magazine. There’s no doubt photography apps have huge momentum on the App Store. With the iPhone 4’s awesome camera and fast processor, taking photos and […] By Marin Todorov.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 5 of this article. Click here to view the first page.

Making Friendly with the Server

Woohoo! You can finally switch to Xcode and do some Objective-C! (Your favorite programming language, right?)

First of all, you need to create a class to talk to the API for you. After a lot of thinking, I decided you should call it “API” :]

So choose from Xcode’s menu “File/New/File…” and choose iOS\Cocoa Touch\Objective-C class as the file type. Click Next, enter “API” as the class name, make it subclass of AFHTTPClient and save it to your project folder.

Since this will be a class that talks to the server over the network, you’re directly subclassing the AFHTTPClient, and you’ll use its capabilities to make POST requests and other goodies.

Open API.h and add this import at the top to use all of the AFNetworking functionality:

#import "AFNetworking.h"

Then above the @interface line, add a define:

//API call completion block with result as json
typedef void (^JSONResponseBlock)(NSDictionary* json);

The above adds a definition of a block, which receives an NSDictionary containing JSON information as a parameter. You use this kind of block for all calls to the API, since the server always returns a JSON response.

Inside the interface definition add the following property to hold the user data, once the user has been authenticated:

//the authorized user
@property (strong, nonatomic) NSDictionary* user;

Then… you’d like to be able to use this class from all the screens in the app. The easiest way to manage this is to make it a Singleton class, so you need a method to access the static instance of the class. Add this method definition above the @end line:

+(API*)sharedInstance;

Finally, you need to add two more methods to get past the user authorization phase (still in API.h). One will be a method to check whether the user is authorized, and the other will be a generic method you will have in the API class to execute commands on the web server.

//check whether there's an authorized user
-(BOOL)isAuthorized;

//send an API command to the server
-(void)commandWithParams:(NSMutableDictionary*)params onCompletion:(JSONResponseBlock)completionBlock;

Next comes the API class implementation! Open API.m, and just above the @implementation directive add these defines:

//the web location of the service
#define kAPIHost @"http://localhost"
#define kAPIPath @"iReporter/"

For the above defines, you will have to change the domain and path if you have any setup other than calling the API from your local machine. The code above will talk to the API if it’s set up exactly as I explained in the text above – local machine web server and subfolder iReporter in the root of the default web site.

Otherwise, you’ll need to change the host and path according to your setup. If you set up a custom domain for this tutorial, and the API files are in the root of the domain instead of being inside a sub-folder, set the path to an empty string.

Just below the @implementation directive, add the user property synthesizer and the method to get the static class instance:

@synthesize user;

#pragma mark - Singleton methods
/**
 * Singleton methods
 */
+(API*)sharedInstance
{
    static API *sharedInstance = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        sharedInstance = [[self alloc] initWithBaseURL:[NSURL URLWithString:kAPIHost]];
    });
    
    return sharedInstance;
}

sharedInstance creates an instance of the API class the first time it’s called, and any subsequent call to the method will just return that instance. There are many different ways to create a singleton class in Objective-C, but since iOS 4.0 (when Grand Central Dispatch or GCD was introduced), this is one of the most straightforward ways to do it. The call to dispatch_once ensures that the shared instance creation is executed only once.

You’ll need a custom init, but it’s gonna be pretty easy. You need to register a default HTTP operation class (you’ll use the default) and instruct the API class to accept only JSON as response. Add this to the end of the file (but before the @end):

#pragma mark - init
//intialize the API class with the destination host name

-(API*)init
{
    //call super init
    self = [super init];
    
    if (self != nil) {
        //initialize the object
        user = nil;
        
        [self registerHTTPOperationClass:[AFJSONRequestOperation class]];
        
        // Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
        [self setDefaultHeader:@"Accept" value:@"application/json"];
    }
    
    return self;
}

The user property just holds the response from the login/register API calls, so that’s a dictionary with all the database columns for the current user (the ones you get back from the API). Here’s a simple check to see if the user is authorized:

-(BOOL)isAuthorized
{
    return [[user objectForKey:@"IdUser"] intValue]>0;
}

Just checking if the login/register call returned anything, and if so whether the IdUser column is a number greater than zero – then the authorization was successful.

All that’s left is the implementation of the call to the server.

Add the following code to the end of API.m:

-(void)commandWithParams:(NSMutableDictionary*)params onCompletion:(JSONResponseBlock)completionBlock
{
    NSMutableURLRequest *apiRequest = 
        [self multipartFormRequestWithMethod:@"POST" 
                                        path:kAPIPath 
                                  parameters:params 
                   constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
                       //TODO: attach file if needed
    }];
    
    AFJSONRequestOperation* operation = [[AFJSONRequestOperation alloc] initWithRequest: apiRequest];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        //success!
        completionBlock(responseObject);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        //failure :(
        completionBlock([NSDictionary dictionaryWithObject:[error localizedDescription] forKey:@"error"]);
    }];
    
    [operation start];
}
  1. First you create an NSMutableURLRequest instance using the parameters you want to send via POST. Note that it’s a mutable instance – you don’t need that just now, but later on when you are adding file upload capability to the API, you’ll need to adjust the request after it has been created; so you just have it ready for the future.
  2. Next you create an operation to handle the network communication in the background and initialize it with the POST request you’ve already prepared.
  3. After the operation is initialized, you set the two blocks to execute on success and failure. When the call is successful, you just pass in the JSON response.
  4. If there is an error and the failure block gets called, you construct a new dictionary holding the message of the network error, and you pass it back – pretty easy.
  5. Finally, you call the start method on the operation, and at that point AFNetworking starts performing its magic in the background.

This is almost the complete API class you’re going to need in your project. As you can see, it’s pretty simple. You’ll make few little adjustments later on, but for now – you’re good to go!

Contributors

Over 300 content creators. Join our team.