cnet w3school filehippo wikipedia yahoo google google google google google google google google google google WELCOME. Thanks for visiting our site. Comment an advise for the development of the site
Related Posts Plugin for WordPress, Blogger...
search below with keywords to find any technical tutorials

How To Create an App Like Instagram With a Web Service Backend

Leave a Comment

In this tutorial, you’ll learn how to make a simple photo sharing app, like an extremely simple version of Instagram. In particular, you’ll learn:
Using a blank startup project that has all the UI already set up, this tutorial will cover how to:
  • How to connect to a JSON-based web API in Objective-C
  • How to create a simple JSON API in PHP
  • How to implement user authorization for the API
  • How to take photos, apply effects and send them over to the JSON service.
Quite a lot of cool stuff, eh? ;]
This tutorial assumes you have prior familiarity with iOS 5 technologies like Storyboards and ARC. If you are not yet familiar with these, now’s the time – check out this tutorial or this tutorial.
You will also need access to a web server with MySQL running. If that sounds intimidating, check out this project, which makes it pretty easy to run a local test server on your Mac.
If you are still feeling insecure about the process of setting up a web server on your Mac, have a look at thisgreat tutorial, which covers all the basics of setting up your development environment.
Without further ado, strike a pose for the camera – and let’s get started!

Getting Started

Download the startup project and extract the contents of the ZIP file to a convenient location on your hard drive. It includes quite few things, so I’ll briefly go over what’s inside.
The project you’re going to develop in this tutorial is called iReporter. It’s an app that gives you the ability to see a stream of all users’ photos, and if you’d like to, register to upload your own photos to the stream.
iReporter has in total four view controllers. Have a look at Storyboard.storyboard in the project file list to get a feeling of what the workflow looks like:
The startup project storyboard
The initial view controller is a navigation controller that shows a screen called StreamScreen after the app launches. This is where you are going to show the stream of all user-uploaded photos.
If you follow the segue going to the screen below, you get to a controller called StreamPhotoScreen. This screen will show up when the user taps a photo thumbnail, and will show a larger-size photo and the photo title.
From StreamScreen there’s a second segue going to the right to a screen called PhotoScreen. On PhotoScreen, you’ll show an action sheet and allow the user to take a photo, apply effects to it and finally post it to the web API.
To be able to do the above, the user will have to authorize themselves to the API. That means when the PhotoScreen appears, in case the user hasn’t logged in yet, you will show a modal screen with the LoginScreen view controller asking the user to either login or register.
Lucky for you, the startup project already includes classes for all of those screens, including connected IBOutlets and IBActions (empty bodies which you will implement during the tutorial).
There are a few more files in the startup project. Inside “Categories,” you’ll find the UIImage categories from Trevor Harmon. You’ll need these to easily resize and crop images. As a side benefit, Trevor’s categories fix the faulty image orientation that sometimes comes from iPhone’s camera! So thanks again Trevor!
I also included a small category which facilitates showing UIAlertView on the screen with a simple message.
As you can see, you’re off to a good start :] Next, you’ll add a third-party library to the project that will handle all the networking for you.

Outsourcing Your App’s Social Life

You can use the good old NSURLConnection class provided by iOS to handle the communication with the web API. But it’s 2012… let’s do something sexier :]
Of the few up-and-coming networking libraries out there for Objective-C, it seems AFNetworking has the most momentum right now, so you’re going to use this one as well. Head over to the AFNetworking Git and download the current version. (Short docs are included on the page, too.)
After downloading, inside the AFNetworking folder you’ll find a subfolder called “AFNetworking.” Just drag and drop it into your project file list. You should get a prompt similar to the following:
Instagram1
Make sure that “Copy items into destination group’s folder (if needed)” is checked so that the AFNetworking files will be copied into your project folder. Click Finish, and you should see the AFNetworking files included in your files list.
AFNetworking files
AFNetworking is not ARC-compatible, but your skeleton project is set to use Automatic Reference Counting (ARC). So you’ll have to set the AFNetworking classes to be non-ARC so that the compiler knows how to handle them.
Select the Xcode project root (as in the picture above), and then switch to the “Build Phases” tab in the right-hand pane. Find and open the “Compile Sources” strip and you’ll see the classes to be compiled within your project.
Scroll down. At the bottom you’ll see all the files for AFNetworking (from AFHTTPClient.m toUIImageView+AFNetworking.m). Select them all (as in the image below), press Enter on the keyboard and in the popup enter “-fno-objc-arc” and click Done. All the AFNetworking files should now be marked as not supporting ARC.
Instagram2
Press Cmd+B now to build the project. If everything is set up correctly, the project should compile successfully. (Except, that is, for a few warnings in the UIImage category classes from Trevor. You can disregard these.)
Note: When you include AFNetworking in your project, you have to go to your project’s .pch and add “#import <SystemConfiguration/SystemConfiguration.h>.” Otherwise, AFNetworking won’t compile. This is already done for you in the startup project, but it’s good to know for the future.

Setting Up the Web API

Now for the other side of the project – the web API. For this, you will need an HTTP server and FTP access to it, and also access to a MySQL server. If you don’t already have those on your Mac, check the link at the top of the article for more details on setting up a local test server on your Mac.
I’ve also prepared a startup project for the web API, so once you have the web server running, go ahead and download the API startup project. Extract the contents of the ZIP file to a location on your hard drive.
The extracted ZIP should contain a few PHP files and a folder named “upload.” The main API file is index.php, and it’s the one you’re going to call from the iPhone app. In api.php, you’re going to add few simple functions to process the user requests, and lib.php contains a couple of functions that will help you with this.
One of them, a function called query, will help you avoid writing too much code. It takes an SQL query and a list of parameters as input, and returns an array containing the results of the SQL query. There’s also a function called thumb that scales down an image and saves the thumbnail.
Upload the folder with the api files to a location on your web server that can be accessed via a browser. Rename the folder to “iReporter,” since that will make things easier to identify. (If you’re doing this on your own machine at home, you can of course just copy the files in Finder to your web folder.) Make sure that the “upload” folder is writable via your PHP scripts, as you’ll be using the folder to save uploaded photos.
Note: You’ll be modifying some of the PHP files for the web service as you proceed through the tutorial. Do note that if you don’t have the web server set up on your Mac and are using a remote server, you’ll need to re-upload the modified files to the server each time you modify them.
Finally, set up the database for the web API. You need two simple tables – one to hold the username and passwords and one to hold the photos. The database table structures are shown below (it’s pretty simple):
SQL database structure
Here’s the SQL file to create the database tables (name the database “iReport”).
Now take one extra step: open up lib.php in your text editor of choice, and have a look at the first couple of lines of code. Depending on how you set up your MySQL server (or how it’s set on your hosting server), you need to edit this code so that PHP knows how to connect to your database server.
The first function, mysqli_connect, takes three parameters. Fill in this information: the first parameter is the name of the database server (leave “localhost” if you’re connecting to a server on your own computer), the second is the MySQL username, and the third is the password. I’ve input some default values working with a blank local installation of MySQL, but as mentioned, you might need to edit those to work with your setup.
On the second line of lib.php, there’s the mysqli_select_db function that takes two parameters: the already-active link to the database server, and the name of the database. If you called your database something other than iReport, change the database name here.
Awesome! You now have skeleton iPhone and web service projects. All that’s left is to write some code to get them to work together.

Registering Users to the Web Service

The plan for the app is to let users upload photos only after they have registered with the app. So the app workflow will go like this:
App workflow
Let’s start with implementing the registration and login to the server. Open up index.php in your favorite text editor. On the line where it says “//API”, add a check for all the possible commands that the API will handle.
Start with register and login. Replace the comment “//API” with:
switch ($_POST['command']) {
 case "login": 
  login($_POST['username'], $_POST['password']); break;
 
 case "register":
  register($_POST['username'], $_POST['password']); break;
 
}
If the POST parameter named “command” holds the login value, you pass the username and password POST parameters to a function called login. The register parameter is treated pretty much the same way, except that the function called is named register. If the client asks for a command the API doesn’t expect, the code execution will simply reach the exit() command at the end of the source file, and no response will be sent to the client.
Note: Don’t panic, we won’t be passing or storing the password as cleartext. (And neither should you!) More on this later :]
Now start with the register command. Open up api.php and add a little helper function for returning errors to the client (the iPhone app). Add this function to api.php within the PHP script tags (“<?” and “?>”):
function errorJson($msg){
 print json_encode(array('error'=>$msg));
 exit();
}
Since the iPhone app expects only JSON responses, you’ll use this little function, which takes a text message and turns it into a JSON response. json_encode is the PHP function that converts PHP objects to JSON – you just feed it an array with the error message, and that’s all.
Now proceed with the register function. First, check if the username exists already. Add the following code to api.php:
function register($user, $pass) {
 //check if username exists
 $login = query("SELECT username FROM login WHERE username='%s' limit 1", $user);
 if (count($login['result'])>0) {
  errorJson('Username already exists');
 }
 
}
On the first line, you create an SQL query to check if there’s a record in the login table with the username given. If there are results, you call errorJson, since you cannot register a user if the username already exists. And that pretty much ends the script, as errorJson dumps the error message and exits the program execution.
Note how the count function in PHP was used to check if there were any results – count returns the number of elements in an array.
OK, so things aren’t so difficult. Add the following to the end of the register method (before the closing curly bracket):
//try to register the user
$result = query("INSERT INTO login(username, pass) VALUES('%s','%s')", $user, $pass);
if (!$result['error']) {
 //success
 login($user, $pass);
} else {
 //error
 errorJson('Registration failed');
}
You use the query helper function again with an SQL command trying to insert a new record to the database. If the query doesn’t return an error (AKA, big success for you) then you just call login.
Why do you call login? Well, you’d like the user to be logged in after successful registration, so why not combine both into one call to the API, right? OK. Time to move to the login function. Wow, you’re moving ahead quite quickly :]
Here’s the whole login function. Add it to api.php, immediately after the register function:
function login($user, $pass) {
 $result = query("SELECT IdUser, username FROM login WHERE username='%s' AND pass='%s' limit 1", $user, $pass);
 
 if (count($result['result'])>0) {
  //authorized
  $_SESSION['IdUser'] = $result['result'][0]['IdUser'];
  print json_encode($result);
 } else {
  //not authorized
  errorJson('Authorization failed');
 }
}
That looks pretty similar to what you already did for register, right?
You run a SELECT SQL command on the login table, and then you check the count of the returned results. If any were found, you have a successful login. Then to create a server session for the logged user, you store their IdUser to the PHP session.
$_SESSION is a special array – everything you store inside will be persisted between different script executions – but only when they were made by the same client. So what you store in the SESSION array is the value of “$result['result'][0]['IdUser']“, which in PHP reads “the value of the IdUser key of the first element of the array stored in the result key.” Or to put it simply, you store the user’s ID, so you know who they are in the following API calls.
Believe it or not, that’s all the PHP code you need to have users register and login to your web service.
Let’s move to the iPhone – because I know just how you’re feeling! ;]
Finally Objective-C!!!

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!

Getting a Little Salty

Select Storyboard.storyboard, and notice how the Photo Stream presents the modal Login dialogue. Next you’re going to authorize the user on this screen, by asking them to login or register with the application.
Photo!
Switch to PhotoScreen.m (it’s inside the Screens folder) and import the API class by adding the following code under the existing #import statement:
#import "API.h"
The above allows you to refer to the API class from within PhotoScreen.
Next, at the end of viewDidLoad, add this code to check whether the user is already authorized:
if (![[API sharedInstance] isAuthorized]) {
    [self performSegueWithIdentifier:@"ShowLogin" sender:nil];
}
Here you just call isAuthorized, which you added just moments ago to the API class. If the user is not authorized, you call the segue called ShowLogin to show the Login screen modally.
If you want to have some fun, run the project and tap on the top right button – this should show the login screen! Fun!
Login or register screen
Of course, if you did the above, then you noticed that neither the Login nor Register buttons work. So switch your focus to the Login screen and add some functionality to it!
First, add a quick usability enhancement. Add a viewDidLoad method like this one to LoginScreen.m just below the @implementation line:
-(void)viewDidLoad {
    [super viewDidLoad];
 
    //focus on the username field / show keyboard
    [fldUsername becomeFirstResponder];
}
Nice! The user doesn’t need to tap on the username field; the keyboard just pops up by itself. That was easy – let’s go on!
At the top of the source file, just below the two import directives add:
#import "API.h"
#include <CommonCrypto/CommonDigest.h>
 
#define kSalt @"adlfu3489tyh2jnkLIUGI&%EV(&0982cbgrykxjnk8855"
Whoa there! What’s that?!
First you import the API class. Then you include the built-in iOS cryptographic library. Okay, makes sense…
The string that looks like rubbish is a salt string that you’re going to use to make the user password a wee bit more difficult to hack. Instead of passing the plaintext password to the server for anyone who dumps the database to easily see, we’ll munge it a bit instead using a technique called hashing with salt.
This is not bulletproofing your server-client model at all, but it’s a good start. If you want to know more about salting the passwords you’re storing, have a look at salting passwords and rainbow tables.
Note: The focus of this tutorial is not on security, so hashing the password with salt is as far as we’re going to go here. Sometime soon, we hope to write another tutorial specifically focused on username/password security with respect to web services ;]
Look for a moment at the login screen. You always have the same text fields: username and password. The only difference between the login and register use cases is the actual call to the API: otherwise the data sent over is the same.
This means you only need one method to handle taps on both the login and register buttons. To determine whether to send a login or register command to the server, you’ll just check which button was tapped.
Both the login and register buttons send a btnLoginRegisterTapped: message to the view controller class. This is going to be a rather long method, so you’ll go through each step carefully. Inside the emptybtnLoginRegisterTapped: in LoginScreen.m, add this code:
//form fields validation
if (fldUsername.text.length < 4 || fldPassword.text.length < 4) {
    [UIAlertView error:@"Enter username and password over 4 chars each."];
    return;
}
 
//salt the password
NSString* saltedPassword = [NSString stringWithFormat:@"%@%@", fldPassword.text, kSalt];
First you do a simple check on the entered username and password to determine whether they’re long enough (you could implement more checks if you wish). Then you add the salt to the password string. The next step is hashing the salted password. Add this code to the method:
//prepare the hashed storage
NSString* hashedPassword = nil;
unsigned char hashedPasswordData[CC_SHA1_DIGEST_LENGTH];
 
//hash the pass
NSData *data = [saltedPassword dataUsingEncoding: NSUTF8StringEncoding];
if (CC_SHA1([data bytes], [data length], hashedPasswordData)) {
    hashedPassword = [[NSString alloc] initWithBytes:hashedPasswordData length:sizeof(hashedPasswordData) encoding:NSASCIIStringEncoding];
} else {
    [UIAlertView error:@"Password can't be sent"];
    return;
}
You declare two variables: hashedPassword will hold the string of the hashed and salted password, while hashedPasswordData is a plain C array, which you will use as an intermediate storage for the hashed data.
Using dataUsingEncoding: you get the data bytes from the salted password. Here’s where the magic happens: CC_SHA1() gets the bytes of the salted password, performs SHA1 hashing on them and stores the result in hashedPasswordData. Next, you quite easily create an NSString out of the data bytes. This is the hashed password you will send to the server.
Phew! The heavy work is done. Now you just need to make the call to the API.
First you should detect whether the user tapped the login or register button, and prepare the correct parameters for the API call. Since the register button has a tag of “1″ (this was set via Interface Builder when the skeleton project was originally created), this is quite easy:
//check whether it's a login or register
NSString* command = (sender.tag==1)?@"register":@"login";
NSMutableDictionary* params =[NSMutableDictionary dictionaryWithObjectsAndKeys: 
 command, @"command",
 fldUsername.text, @"username",
 hashedPassword, @"password",
 nil];
Now that you have all the parameters for the call prepared, it’s really easy to make the actual call:
//make the call to the web API
[[API sharedInstance] commandWithParams:params
                           onCompletion:^(NSDictionary *json) {
                           //handle the response
 
                           }];
The result from the server (or an error if there was a communication problem) will be passed as an NSDictionary to the block above. Let’s dive into handling that response. Replace the “//handle the response” comment with:
//result returned
NSDictionary* res = [[json objectForKey:@"result"] objectAtIndex:0];
 
if ([json objectForKey:@"error"]==nil && [[res objectForKey:@"IdUser"] intValue]>0) {
   //success
 
} else {
   //error
   [UIAlertView error:[json objectForKey:@"error"]];
}
json is an NSDictionary and, as per the PHP API code you wrote earlier, it should hold a result key. You fetch another dictionary from within this key – hopefully that’s the info of the logged user!
You then check whether an error has been returned, or if the user info is invalid, and if so, you display an error alert. Otherwise, you log in the user and take him/her to the Photo screen. To do that, replace the “//success” line with:
[[API sharedInstance] setUser: res];
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
 
//show message to the user
[[[UIAlertView alloc] initWithTitle:@"Logged in" 
                           message:[NSString stringWithFormat:@"Welcome %@",[res objectForKey:@"username"] ]
                         delegate:nil 
                cancelButtonTitle:@"Close" 
                 otherButtonTitles: nil] show];
You store the user data to the API class and dismiss the Login dialogue. A nice alert also pops up to congratulate the user by their name. Sweet!
To recap: if the user wants to register with the system, this method will register and log them in at the same time. Alternatively, the user can use an existing user account and password to simply log in to the system. If the login was unsuccessful, you show the error message from the server. It’s all so very easy :]
That’s an awesome job so far! Everything should work right now, so fire up the project and go to the login screen. Choose a username and a password and tap on register. If you have a working server environment, you should see the Login screen disappear and the Photo screen should be now accessible! Awesome!
Logged in the app

I’m Ready for Some Files, Baby

Switching back to the web service, you’re going to go on with the part of the web service that accepts photos submitted by the users and stores them on the server. First you need to add the code to handle the upload command.
Open up index.php and add a new case in the switch command:
case "upload":
 upload($_SESSION['IdUser'], $_FILES['file'], $_POST['title']);break;
In case the upload command of the API is being called, you take the user ID from the user session, and you send it to the upload function along with the submitted file (from the $_FILES array in PHP) and the title the user provided for that photo.
Ah! The upload function. No problem at all.
Open up api.php. Here’s where you’re going to add the aforementioned function. At the bottom of the file add this code:
function upload($id, $photoData, $title) {
 //check if a user ID is passed
 if (!$id) errorJson('Authorization required');
 
 //check if there was no error during the file upload
 if ($photoData['error']==0) {
  $result = query("INSERT INTO photos(IdUser,title) VALUES('%d','%s')", $id, $title);
  if (!$result['error']) {
 
   //inserted in the database, go on with file storage
 
  } else {
   errorJson('Upload database problem.'.$result['error']);
  }
 } else {
  errorJson('Upload malfunction');
 }
}
This is the first part of the code you need in order to do the photo upload. Let’s see where you are:
  1. Since this is a protected method (i.e. accessible only to logged in users) you check if there is a user ID stored in the session (the $id parameter passed to the function).
  2. $photoData (an array) is being populated by PHP with the file upload details. You check the error key to see if the upload succeeded. If there was an error, there’s no sense in going on with inserting data in the database.
  3. If the upload is OK, you go on with inserting the title of the photo and the user ID in the database.
  4. You’re going to use the automatically-created ID in the database table “photos” as an identifier for the photo file itself. You’ll see this in a moment.
  5. If the database insert was successful, you go on with saving the file – you see the comment where the code will be.
As you can see, every step in the upload process so far can fail in a different way, so you already have three if-else statements that use errorJson to return different fail responses. In decoupled systems (like your client-server app), much more can go wrong in the workflow compared to ordinary software, so having good error-handling logic is essential if you want to build even a moderately complicated application.
Now add the code to store the uploaded files on the server.
First you need to get hold of a link to the database, so you can get the automatically generated ID in the photos table. Luckily, lib.php already grabs a link to the database for you, so just use that. The link is called “$link” and is found in the global variable namespace.
Add the code and see how it works. Replace the “//inserted in the database…” comment with:
 //database link
 global $link;
 
 //get the last automatically generated ID
 $IdPhoto = mysqli_insert_id($link);
 
 //move the temporarily stored file to a convenient location
 if (move_uploaded_file($photoData['tmp_name'], "upload/".$IdPhoto.".jpg")) {
  //file moved, all good, generate thumbnail
  thumb("upload/".$IdPhoto.".jpg", 180);
  print json_encode(array('successful'=>1));
 } else {
  errorJson('Upload on server problem');
 };
You call mysqli_insert_id, which returns the last auto-generated ID in the database – namely, the ID of the newly saved photo record.
When you upload a file to the server using PHP, the file is saved to a temporary location on the server, and the path to that location is passed to the PHP script handling the upload via the $_FILES array. You then callmove_uploaded_file, which (as the name describes pretty well) moves the newly uploaded photo file from its temporary location to the folder where you want it to be.
You rename the file, following the [database id].jpg format so that the file name always corresponds to the database ID for the file record. Then you call the nifty thumb function to generate a nice thumbnail of the full-size photo.
Finally, if all went well, you return a JSON response with the key “successful.” That lets the iPhone app know that all is well, the photo was uploaded successfully, and that it was saved to the system.

In this second and final part of the tutorial, you get to do the cool stuff – taking photos, applying effects and uploading files to the server.
Grab some tasty breakfast like mine, and let’s go!

Getting Started: the Photo Screen

All right, it’s time to fire up the iPhone camera, capture some action and submit the results to the server via the API!
Open the tutorial project in Xcode and take a look at Storyboard.storyboard. What you have (already prepared) on the Photo Screen is a UIImageView where you’ll show the preview of the photo taken, a UITextField where the user can enter a title for the photo, and an action button that displays the screen menu. That’s everything you need for your photo app!
Switch to PhotoScreen.m and find btnActionTapped:. It’s empty, so add the code to show a menu of options when the action button is tapped:
[fldTitle resignFirstResponder];
 
//show the app menu
[[[UIActionSheet alloc] initWithTitle:nil
                             delegate:self
                    cancelButtonTitle:@"Close"
               destructiveButtonTitle:nil
                    otherButtonTitles:@"Take photo", @"Effects!", @"Post Photo", @"Logout", nil] 
 showInView:self.view];
First you make sure there’s no on-screen keyboard present. Since there’s only one text field, just calling resignFirstResponder on it should be enough.
Then you show an action sheet with all the possible actions the user can perform:
Photo screen menu
  1. Take Photo – Invoke the standard camera dialog of iOS.
  2. Effects! – You’ll borrow some code from my colleague Jacob Gundersen‘s tutorial on applying effects to images in order to apply a Sepia effect to the user’s photo.
  3. Post Photo – Send the photo to the server using an API call.
  4. Logout – End the user session with the server.
You need to implement a UIActionSheet delegate method to handle taps on the different buttons in the sheet. But before you do that, you need to set up a few methods to handle each of the above actions. Above the @implementation directive, add the private definitions for those methods as follows:
@interface PhotoScreen(private)
-(void)takePhoto;
-(void)effects;
-(void)uploadPhoto;
-(void)logout;
@end
Now add this code to the end of the file to implement UIActionSheet:
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    switch (buttonIndex) {
        case 0:
            [self takePhoto]; break;
        case 1:
            [self effects];break;
        case 2:
            [self uploadPhoto]; break;
        case 3:
            [self logout]; break;
    }
}
Build and run the project, log in and tap on the action button at the right of the tab bar. The menu should look something like this:
Instagram3
Start by implementing the first item: Take Photo.

Be a Photo-Snapping Beast

For those of you who’ve never interacted with the iPhone’s camera programmatically, it’s actually very easy. There’s an Apple standard view controller, which you only need to instantiate, set up and then present modally. Whenever the user takes a photo or cancels the process, callback methods on your class are called to handle the action.
Add the takePhoto method to the end of PhotoScreen.m:
-(void)takePhoto {
    UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
#if TARGET_IPHONE_SIMULATOR
    imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
#else
    imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
#endif
    imagePickerController.editing = YES;
    imagePickerController.delegate = (id)self;
 
    [self presentModalViewController:imagePickerController animated:YES];
}
UIImagePickerController is the view controller that allows the user to use the camera. As with any normal class, you make a new instance.
Next you set up the sourceType property – you can instruct the dialog whether the user should actually use the camera or can choose from the Photos library on the device. In the code above I snuck in some code to detect whether the app is running on the iPhone simulator and if so, the dialog just accesses the Photo library. (Because, you know… there’s no camera on the simulator.)
Setting “editing” to YES allows the user to do simple editing operations on the photo before accepting it.
Finally, you present the camera dialog as a modal view and you leave the user in Apple’s hands. Next time you hear from the user, it’ll be in the methods handling response from the camera dialog.
You will be doing some scaling down and cropping of the images the users take with the camera, so you need to import few handy UIImage categories. Scroll to the top of the file and below the other imports, add this one:
#import "UIImage+Resize.h"
Now implement two UIImagePickerControllerDelegate methods. Add the following to the end of the file:
#pragma mark - Image picker delegate methdos
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
 UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
    // Resize the image from the camera
 UIImage *scaledImage = [image resizedImageWithContentMode:UIViewContentModeScaleAspectFill bounds:CGSizeMake(photo.frame.size.width, photo.frame.size.height) interpolationQuality:kCGInterpolationHigh];
    // Crop the image to a square (yikes, fancy!)
    UIImage *croppedImage = [scaledImage croppedImage:CGRectMake((scaledImage.size.width -photo.frame.size.width)/2, (scaledImage.size.height -photo.frame.size.height)/2, photo.frame.size.width, photo.frame.size.height)];
    // Show the photo on the screen
    photo.image = croppedImage;
    [picker dismissModalViewControllerAnimated:NO];
}
 
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    [picker dismissModalViewControllerAnimated:NO];
}
Have a look at imagePickerController:didFinishPickingMediaWithInfo: first:
  1. All information about the image is passed via the info dictionary. So you have to first get the image from the dictionary.
  2. Then, you call resizedImageWithContentMode:bounds:interpolationQuality: to get a scaled-down image of the user’s photo. (This method also fixes wrong camera image orientation, as often happens.)
  3. Next you crop the image (which is a rectangle) to a square format by calling croppedImage: on the scaled image. Square photos are all the rage these days and you want only the best for your app :]
  4. You show the scaled and cropped image in the image view.
  5. Finally, you hide the camera dialog.
If the user cancels the process of taking a photo, imagePickerControllerDidCancel: will be invoked. All you actually need to do is dismiss the camera dialog.
That’s it! Fire up the app (either on device or simulator) and try taking some photos.
Note: You’ll only be able to use the camera on a device. If you’re testing the app on the simulator, you need one or more photos in your photo library on the simulator in order to do anything. Plus, if you’ve got your web server on your local machine, you won’t be able to access the web server via the http://localhost URL you specified in API.m. Instead, you’ll have to change the URL to indicate your machine’s IP address.
You can add new photos to the simulator by simply dragging and dropping an image onto the simulator. This will show the image in mobile Safari. Then, simply tap on the image and hold until you get an Action Sheet allowing you to save the image to the simulator’s photo library :]
First photo taken with iReporter

Send My Breakfast Back In Time

This tutorial will take you through implementing only one effect, but you are certainly encouraged to read more on the topic and implement more effects on your own.
The code to follow takes the photo loaded in the image view and applies a sepia effect to it. The code is taken from the Beginning Core Image tutorial, so if you are interested you can read more about it here.
Add the following method below takePhoto in PhotoScreen.m:
-(void)effects {
    //apply sepia filter - taken from the Beginning Core Image from iOS5 by Tutorials
    CIImage *beginImage = [CIImage imageWithData: UIImagePNGRepresentation(photo.image)];
    CIContext *context = [CIContext contextWithOptions:nil];
 
    CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone" 
                                  keysAndValues: kCIInputImageKey, beginImage, 
                        @"inputIntensity", [NSNumber numberWithFloat:0.8], nil];
    CIImage *outputImage = [filter outputImage];
 
    CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
    photo.image = [UIImage imageWithCGImage:cgimg];
 
    CGImageRelease(cgimg);
}
Build and run the project again to see some cool stuff happening! Take a photo, tap the action button and choose Effects! Pretty cool, isn’t it? Thank you, Jacob!
Sepia!

Your Place in the Cloud

To get this part of the application running, you have to step back for a second and finish the API class. Remember how I was saying you would be handling file uploads through the API? But you haven’t implemented the functionality yet. So open API.m and find commandWithParams:onCompletion:
It’s easy to spot the place where the code is supposed to go – there’s a handy comment left in the source code. However, you’re going to make a few amendments to the method body first. Here you go!
At the very beginning of the method body, add these few lines:
NSData* uploadFile = nil;
if ([params objectForKey:@"file"]) {
    uploadFile = (NSData*)[params objectForKey:@"file"];
    [params removeObjectForKey:@"file"];
}
This piece of code checks whether the API command gets a “file” param. If yes, it takes the file parameter out of the params dictionary and stores it separately. This is due to the fact that while all the other parameters are going to be sent as normal POST request variables, the photo contents will be sent separately as a multipart attachment to the request.
Now look at the block where you currently have only the “//TODO: attach file if needed” comment. Replace the comment with the following code:
if (uploadFile) {
   [formData appendPartWithFileData:uploadFile 
                               name:@"file" 
                           fileName:@"photo.jpg" 
                           mimeType:@"image/jpeg"];
}
The code’s pretty simple: you just add the binary contents of the file, a name for the request variable, the file name of the attachment (you’ll always pass photo.jpg for this), and a mime type to the request you’ll be sending to the server.
That’s about everything you need to add to handle file uploads! Easy-peasy.
Go back to PhotoScreen.m and add a new method to the class (the one called upon tapping Post Photo, of course):
-(void)uploadPhoto {
    //upload the image and the title to the web service
    [[API sharedInstance] commandWithParams:[NSMutableDictionary dictionaryWithObjectsAndKeys: 
                                             @"upload",@"command",
                                             UIImageJPEGRepresentation(photo.image,70),@"file",
                                             fldTitle.text, @"title",
                                             nil] 
     onCompletion:^(NSDictionary *json) {
 
  //completion
 
     }];
}
Now that the API supports file uploads, you just pass the parameters to it: the API command is “upload”; as the “file” parameter you pass the JPEG representation of the photo; and the title of the photo is taken from the text field in the user interface.
Now you reach another level of complexity: you authorize the user before they open the Photo screen, but hey! There’s no guarantee that the user is still authorized when they get to the point of uploading a photo.
Maybe the app stayed in the background for half a day, and then the user opened it up again and decided to upload a photo. Or maybe something else. But you don’t know.
So the “upload” call may now fail for more reasons than just network communication errors – it may also fail because the user session expired. You’ll have to handle that in a reasonable way to provide a good user experience.
First, add the following import to the top of the file:
#import "UIAlertView+error.h"
Next, inside the completion block in uploadPhoto, add the code to handle the server response:
 //completion
 if (![json objectForKey:@"error"]) {
 
     //success
     [[[UIAlertView alloc]initWithTitle:@"Success!" 
                                message:@"Your photo is uploaded" 
                               delegate:nil 
                      cancelButtonTitle:@"Yay!" 
                      otherButtonTitles: nil] show];
 
 } else {
     //error, check for expired session and if so - authorize the user
     NSString* errorMsg = [json objectForKey:@"error"];
     [UIAlertView error:errorMsg];
 
     if ([@"Authorization required" compare:errorMsg]==NSOrderedSame) {
         [self performSegueWithIdentifier:@"ShowLogin" sender:nil];
     }
 }
Let’s see: if the result doesn’t have a key called “error”, you assume the call was successful. You show the user a nice alert letting them know the operation was successful.
In the else branch, you store the error message in errorMsg and show it again using an alert. Then you compare the error message to the string “Authorization required” (it’s what the server will return when the user session doesn’t exist) and if that’s the case, you invoke the segue to show the Login screen.
What will happen in that case? The photo the user has taken will remain loaded in the UIImageView, the title will remain in the text field… and if the user authorizes herself successfully with the API, the Login screen will disappear and the user will have another chance to try to upload the photo to the server. Pretty cool!!!
The photo has been successfuly uploaded
You’re almost done with this screen’s functionality.

Get Me Outta This Joint

Last (but not least) the user should always be able to log out. There are two steps to logging the user out:
  1. Destroy the “user” property in the API class.
  2. Destroy the user session on the server side.
Start with the Objective-C code. Add the following to PhotoScreen.m:
-(void)logout {
//logout the user from the server, and also upon success destroy the local authorization
[[API sharedInstance] commandWithParams:[NSMutableDictionary dictionaryWithObjectsAndKeys: 
                                         @"logout",@"command",
                                         nil]
                           onCompletion:^(NSDictionary *json) {
 
                               //logged out from server
                               [API sharedInstance].user = nil;
                               [self performSegueWithIdentifier:@"ShowLogin" sender:nil];
                           }];
}
You send the “logout” command to the server, and upon success you destroy the user data on the iPhone side. Since the user can’t do anything anymore on this screen (when not logged in), you give him the opportunity to login immediately as someone else by invoking the login screen segue.
There’s also a bit of work to be done on the server side. Open index.php from the web project, and add one more case to the “switch” statement:
case "logout":
 logout();break;
Now switch to api.php and at the end add the logout() function that you call from index.php:
function logout() {
 $_SESSION = array();
 session_destroy();
}
Pretty easy! All the per-user data kept on the server side is stored in the $_SESSION array. You erase the data by saving an empty array to $_SESSION, and the data is gone! Poof! You also call session_destroy() to make 101% sure the user session is no more. That’s all you need to do.
Congratulations! You’ve made it pretty far through this kind-of-heavy Objective-C/PHP ping-pong. But hey, glory awaits you! There’s just a little bit more to do and the app will be fully functional!
Fire up the app and play around – you deserve it! Take photos, apply effects, upload images to the server, and even log out and log back in. Cool!
However, there’s no way to see the photos you’ve saved to the server. That’s no fun!
Have no fear! Next, you are going to use that first screen of the app to show the photo stream. (You kind of had to implement the upload functionality first, or there’d be no photos to display in the stream!)

Streaming All Day, All Night

The plan for the stream functionality is to show the last 50 photos uploaded by all users.
Remember that you were so smart as to also generate thumbnails for the uploaded photos? That comes in handy right about now – on the stream screen. You’ll be loading only the thumbnails of the photos and showing a list on the Stream Screen.
But enough with the plans; get to doing! Open index.php (one last time) and add the final case to the switch statement:
case "stream":
 stream((int)$_POST['IdPhoto']);break;
There’s something strange here, right? Why does the stream command of the API take an “IdPhoto” parameter?
You’re going to use the same call for two different purposes. If there are no parameters, the API will return the last 50 photos as planned. If IdPhoto is provided, you’ll return the data for that single photo (i.e. when the user wants to see the full-sized photo of a thumbnail).
Switch to api.php and add the stream() function:
function stream($IdPhoto=0) {
 if ($IdPhoto==0) {
  $result = query("SELECT IdPhoto, title, l.IdUser, username FROM photos p JOIN login l ON (l.IdUser = p.IdUser) ORDER BY IdPhoto DESC LIMIT 50");
 } else {
  $result = query("SELECT IdPhoto, title, l.IdUser, username FROM photos p JOIN login l ON (l.IdUser = p.IdUser) WHERE p.IdPhoto='%d' LIMIT 1", $IdPhoto);
 }
 
 if (!$result['error']) {
  print json_encode($result);
 } else {
  errorJson('Photo stream is broken');
 }
}
As you can see, you’re again going for the simplest solution. You check if the parameter IdPhoto is equal to zero. If yes, you just query the last 50 photos. Otherwise, you try to fetch the requested photo.
You check if there was no error (i.e. big success) and send the result from the database to the iPhone app. Luckily, showing the photos inside the app is not so difficult!
Your goal is to create a listing of photo thumbnails and show them in a table-like layout. When the user taps one of them, you will invoke a segue to open the full-size version of the thumbnail.
You will develop a new custom thumbnail view that will show the photo thumb, the username, and will also automatically calculate its position and react to touches! The final layout of the screen will look like this:
The photo stream
From Xcode’s menu, choose File/New/File…, and select the Objective-C class template. Make the new class inherit UIButton (because you want the new view to handle touches) and call it PhotoView. Open upPhotoView.h and replace everything inside with:
#import <UIKit/UIKit.h>
 
//1 layout config
#define kThumbSide 90
#define kPadding 10
 
//2 define the thumb delegate protocol
@protocol PhotoViewDelegate <NSObject>
-(void)didSelectPhoto:(id)sender;
@end
 
//3 define the thumb view interface
@interface PhotoView : UIButton
@property (assign, nonatomic) id<PhotoViewDelegate> delegate;
-(id)initWithIndex:(int)i andData:(NSDictionary*)data;
@end
Here’s what the above does:
  1. First, you need some constants – since the photos are square, you define only the width of the thumbnail. You have 90px as the thumbnail width and therefore you will have a layout of 3 columns on the screen (you have 270x width for 3 columns plus 20px for the 2 margins between the columns).
  2. Next, you define a protocol for the thumbnail view to communicate with your controller. You have one method the controller has to implement: didSelectPhoto:. Whenever the user taps on a thumbnail, the thumb view will let its delegate know that it was tapped. Then the controller can open up the full-size photo screen. You’ll make the Stream Screen view controller conform to this protocol later on.
  3. Finally, you define the interface of the class. You need a property to hold a reference to the delegate. Since the PhotoView instances are going to be directly added in the view hierarchy of the view controller, which will be the delegate, you use assign for the property.
Your custom initializer for the class will take an index. This index will be used to calculate the row and column on which the thumbnail appears. It’ll also get the photo data and make a request to the server to fetch the full-size photo.
Let’s get to implementing all this!
There are a couple of things to do in PhotoView.m:
//add under #import "PhotoView.h"
#import "API.h"
 
//add under @implementation
@synthesize delegate;
Now you’re going to take a little detour and add one short method to the API class. You want it to give you back the URL of an image on the server by getting the ID of the photo you want to load. Add the method in the respective interface and implementation files of the API class:
//in API.h
-(NSURL*)urlForImageWithId:(NSNumber*)IdPhoto isThumb:(BOOL)isThumb;
 
//in API.m
-(NSURL*)urlForImageWithId:(NSNumber*)IdPhoto isThumb:(BOOL)isThumb {
    NSString* urlString = [NSString stringWithFormat:@"%@/%@upload/%@%@.jpg",
                           kAPIHost, kAPIPath, IdPhoto, (isThumb)?@"-thumb":@""
                           ];
    return [NSURL URLWithString:urlString];
}
Since you’re uploading all images into the “upload” folder, your method generates the full URL, including the server host and path. Also, depending on whether you want to fetch the thumbnail or the full-size format, it takes care to provide the correct file name in the URL returned.
Note: This tutorial covers the basics of a web-back-end/iPhone-client. These basics will give you a good understanding of how to model and design your product. But I need to mention that creating a real-life photo-sharing application takes a bit more expertise, especially when it comes to file storage.
I can’t cover all details here, but I really want to give you some pointers on where you might expect problems with file storage services.
  1. First of all, using the database IDs as filenames is good in order to get things working, but you should have a different approach for a production environment. If you use incremental numbers and store all files in the same folder, it is then relatively easy for someone to fetch all the photos from your server (and you might not necessarily want that).
  2. Furthermore, storing tons of photos on your own server will probably generate a lot of traffic. If you have one of those all-inclusive hosting packs you might not care for that, but from experience I know those types of offers tend to provide variable quality over time. What you’d like to have for a large-scale photo sharing web service is a distributed CDN, so you can provide speed and quality to your users around the world.
  3. Not to be overlooked is the file structure of the files stored. Having 500,000 files in a single folder is not a good idea – this makes it incredibly difficult to administer the content (this also applies when the files are located on a CDN). What you would like to do is distribute the uploaded photos into a balanced tree-like folder structure, so you can easily track the location of a single photo, and so the file folders are a manageable size.
  4. You will also want to check the content of the file being sent over. Storing user files on your servers is always dangerous. At the least, you need to check whether the file has a valid JPG format header, so you know it’s not anything harmful somebody is uploading through the API. Best is to do image processing on the server side, so you make sure you don’t keep the content as it was sent to you.
With that said, let’s go back to your app! You still need to implement the thumbnail view – the only method left is the custom initializer. Add it now in two easy steps. Open PhotoView.m and add:
-(id)initWithIndex:(int)i andData:(NSDictionary*)data {
    self = [super init];
    if (self !=nil) {
        //initialize
        self.tag = [[data objectForKey:@"IdPhoto"] intValue];
 
        int row = i/3;
        int col = i % 3;
 
        self.frame = CGRectMake(1.5*kPadding+col*(kThumbSide+kPadding), 1.5*kPadding+row*(kThumbSide+kPadding), kThumbSide, kThumbSide);
        self.backgroundColor = [UIColor grayColor];
 
        //add the photo caption
        UILabel* caption = [[UILabel alloc] initWithFrame:
                            CGRectMake(0, kThumbSide-16, kThumbSide, 16)
                            ];
        caption.backgroundColor = [UIColor blackColor];
        caption.textColor = [UIColor whiteColor];
        caption.textAlignment = UITextAlignmentCenter;
        caption.font = [UIFont systemFontOfSize:12];
        caption.text = [NSString stringWithFormat:@"@%@",[data objectForKey:@"username"]];
        [self addSubview: caption];
 
  //step 2
    }
    return self;
}
This code should be pretty simple to understand – it’s mostly UI-related. Let’s go over it briefly:
  1. You store the ID of the photo in the tag property for future use.
  2. You calculate the row and the column based on the index of the photo (i.e. the 7th photo in the list is located on the 1st column of the 3rd row).
  3. You then calculate the frame of the view based on its row/column position, using the constants for the thumbnail side and the margin you want to have between the columns.
  4. You then add a UILabel that will show the name of the user who uploaded the photo.
You’ve taken care of the layout! Now continue adding functionality to the thumbnail. Add the following in place of the “//step 2″ comment:
//add touch event
[self addTarget:delegate action:@selector(didSelectPhoto:) forControlEvents:UIControlEventTouchUpInside];
 
//load the image
API* api = [API sharedInstance];
int IdPhoto = [[data objectForKey:@"IdPhoto"] intValue];
NSURL* imageURL = [api urlForImageWithId:[NSNumber numberWithInt: IdPhoto] isThumb:YES];
 
AFImageRequestOperation* imageOperation = 
    [AFImageRequestOperation imageRequestOperationWithRequest: [NSURLRequest requestWithURL:imageURL]
                                                      success:^(UIImage *image) {
                                                          //create an image view, add it to the view
                                                          UIImageView* thumbView = [[UIImageView alloc] initWithImage: image];
                                                          thumbView.frame = CGRectMake(0,0,90,90);
                                                          thumbView.contentMode = UIViewContentModeScaleAspectFit;
                                                          [self insertSubview: thumbView belowSubview: caption];
                                                      }];
 
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:imageOperation];
First of all, you handle touches by directly invoking didSelectPhoto: on the delegate (you don’t really need any extra methods in PhotoView).
Then you grab a reference to the shared API instance, get the IdPhoto value out of the photo data passed to the initializer, and finally you call urlForImageWithId:isThumb: (which you added moments ago to the API class) to get the URL of the image on the server.
You’re finally ready to fetch the image from the web and show it inside the view. AFNetworking defines a custom operation to load remote images, so that’s what you’re going to use. All you do is provide an NSURLRequest with the image URL and a block to be executed when the image is fetched. Inside the block, you create a UIImageView, load the fetched image, add the image view to your PhotoView instance and … voila! That’s all!
Well… not quite all. The operation is ready to be executed, but not just yet. In the final couple of lines of code, you initialize a new operation queue and add the operation to the queue. Now that’s really all!
Your custom thumbnail is pretty awesome and it does everything by itself for you. I personally really like having such handy components around. What’s left is to show some of those nifty thumbnails on the Stream Screen!
Open StreamScreen.m (inside the Screens folder) and at the top under the single #import, add a few more:
#import "API.h"
#import "PhotoView.h"
#import "StreamPhotoScreen.h"
You’re including the API class (of course!), your new custom thumb component and the class to show the full-size photo.
You need a couple of private methods in the class, so below the imports also add the private interface:
@interface StreamScreen(private)
-(void)refreshStream;
-(void)showStream:(NSArray*)stream;
@end
You have to make a call to the server and show the thumbs immediately after the user opens the app, so invoke the method doing this in viewDidLoad. At the end of viewDidLoad add:
//show the photo stream
[self refreshStream];
Next add the refreshStream method itself to the end of the file (but before the @end):
-(void)refreshStream {
    //just call the "stream" command from the web API
    [[API sharedInstance] commandWithParams:[NSMutableDictionary dictionaryWithObjectsAndKeys: 
                                             @"stream",@"command",
                                             nil] 
                               onCompletion:^(NSDictionary *json) {
                                   //got stream
                                   [self showStream:[json objectForKey:@"result"]];
                               }];
}
By now, you should be absolutely familiar with what’s going on in this piece of code. Sending the “stream” command to the server API, getting back a list of photos as JSON, and passing the JSON to showStream:.
Next add the implementation for showStream::
-(void)showStream:(NSArray*)stream {
    // 1 remove old photos
    for (UIView* view in listView.subviews) {
        [view removeFromSuperview];
    }
    // 2 add new photo views
    for (int i=0;i<[stream count];i++) {
        NSDictionary* photo = [stream objectAtIndex:i];
        PhotoView* photoView = [[PhotoView alloc] initWithIndex:i andData:photo];
        photoView.delegate = self;
        [listView addSubview: photoView];
    }    
    // 3 update scroll list's height
    int listHeight = ([stream count]/3 + 1)*(kThumbSide+kPadding);
    [listView setContentSize:CGSizeMake(320, listHeight)];
    [listView scrollRectToVisible:CGRectMake(0, 0, 10, 10) animated:YES];
}
  1. First you remove all subviews in the “listView” UIScrollView. You need to do this because you call this same method when the user wants to refresh the photo stream, so there might be photos inside the scroll view already.
  2. You use a for loop over the returned photo records to fetch the photo data, and then create a PhotoView instance with it. Since PhotoView takes care of everything for you, you just need to set the view controller as delegate and add the thumbnail as a subview.
  3. Finally, you update the height of the scroll view. It’s pretty easy since you know how many thumbnails you have in total and how many rows they would occupy. You also scroll the list to the top (where new photos appear).
OK, one final touch! You should have a little warning on the line where you set the thumb’s delegate. Yes, you get it because the view controller does not conform to the required protocol. Quickly switch toStreamScreen.h and fix that:
//under the import clause
#import "PhotoView.h"
 
//at the end of the @implementation line
<PhotoViewDelegate>
Sweet! That fixes it. Hey, there’s further good news – the Stream Screen is now functional! If you’ve already uploaded a few photos to the server, fire up the project and you should see the thumbnails appearing on the main app screen. Congrats! You’ve made it through this long journey!
Tapping on the thumbnails doesn’t really work though, does it? Nope… that was a premature celebration!
You need to add the didSelectPhoto: method to the view controller, in StreamScreen.m. Just call the segue to show the full-size photo. But there’ll be a little extra work to prepare the segue, so you’ll also need a prepareForSegue:sender: method:
-(void)didSelectPhoto:(PhotoView*)sender {
    //photo selected - show it full screen
    [self performSegueWithIdentifier:@"ShowPhoto" sender:[NSNumber numberWithInt:sender.tag]];   
}
 
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([@"ShowPhoto" compare: segue.identifier]==NSOrderedSame) {
        StreamPhotoScreen* streamPhotoScreen = segue.destinationViewController;
        streamPhotoScreen.IdPhoto = sender;
    }
}
Here you do a little trick. When a thumbnail is selected, you fetch its tag property, which holds the photo ID, and you make a number out of it, which you then in turn pass as the sender for the segue (very cocky). It’s just a shortcut to send a parameter to the prepareSegue method.
In prepareForSegue, you check if it’s the segue to show the full-size photo (by checking its identifier), and if so, you pass the IdPhoto to the StreamPhotoScreen, which is the target screen for this segue. This should be enough to connect the thumb with the full-size photo screen.
Just a small tweak to the interface – tapping on the refresh button at the top left calls btnRefreshTapped, but the method body is empty. What you need to refresh (aha!) is just to call refreshStream. So go tobtnRefreshTapped and add the following:
[self refreshStream];
Now you can handle showing the stream, and taps on the thumbnails. Also note that the refresh button on the top left corner is connected to refreshStream, so the user can refresh the stream whenever they want.
Not so much is left now, just a little more patience and effort. But things are coming to a wrap, so no worries! :]
If you open StreamPhotoScreen.h, you’ll see the IdPhoto property is already in place, so passing the ID from the Stream Screen to the full-size photo screen is already in place. All you need to do is talk to the server to get the full-size photo, and then just load the full-size photo inside the image view on the screen.
Switch to StreamPhotoScreen.m and make the following changes:
// 1. under the #import clause
#import "API.h"
 
// 2. inside the implementation
-(void)viewDidLoad {
API* api = [API sharedInstance];
 
//load the caption of the selected photo
[api commandWithParams:[NSMutableDictionary dictionaryWithObjectsAndKeys: 
                         @"stream",@"command",
                         IdPhoto,@"IdPhoto",
                         nil] 
 
           onCompletion:^(NSDictionary *json) {
 
               //show the text in the label
               NSArray* list = [json objectForKey:@"result"];
               NSDictionary* photo = [list objectAtIndex:0];
               lblTitle.text = [photo objectForKey:@"title"];
           }];
 
//load the big size photo
NSURL* imageURL = [api urlForImageWithId:IdPhoto isThumb:NO];
[photoView setImageWithURL: imageURL];
}
When the view has loaded, you make the same call to the API as on the Stream Screen, but you also pass the ID of the desired photo as a parameter. If you remember, when this parameter is present the API returns only the data for this particular file.
When you get a response back from the API call, you take the photo data and show the photo title inside the UILabel (created in your storyboard file) lblTitle.
Ah! One final step: to actually load the photo in the image view. Thanks to AFNetworking, it’s pretty easy. AFNetworking defines a category on UIImageView and adds the handy method used above in the code,setImageWithURL:, which fetches a remote image from the web and loads it in the UIImageView.
Now it’s all in place. Fire up the project – see the stream, tap on photos and see their details. Also take photos and upload them! This is an awesome start on your way to creating a killer photo-sharing application!
Full size photo

Where To Go From Here?

The complete source code of the project you developed – both Xcode and PHP parts – can be found in this archive.