How To Create an App Like Instagram With a Web Service Backend – Part 2/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. Ready to go on building your photo-sharing iPhone app? Last time, in first part of the tutorial, you created the basics of the web […] By Marin Todorov.

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

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!)

Contributors

Over 300 content creators. Join our team.