How To Easily Create A Web Backend for Your Apps with Parse

Antonio Martínez
Learn how to make a simple app with a web back-end made with Parse!

Learn how to make a simple app with a web back-end made with Parse!

This is a post by Tutorial Team Member Antonio Martínez, a mobile software developer currently working as an iOS Developer in London.

In my previous article, you learned about some of the backend service providers available today and what types of features you can expect from them.

Now it’s time to start working with one of them in detail! In this part of the tutorial, you will build an app using the Parse backend service.

You will build the same Photo Sharing app from the previous article – including user logins, photo uploads, and a photo wall. But this time, all the BaaS functionality will be added step-by-step by you!

To keep the focus on Parse, you’ll begin with a starter project that has the user interface pre-created, but no capability to upload or download any images. You will add the Parse service piece by piece until you have a functioning app.

Ready to build an app with a web backend, the easy way? Great! Then let’s get started with Parse! :]

First Things First — Creating Your Backend Service

Before starting the development of your app, the first step is to create an app in the Parse backend. Every developer and every app requires a unique identifier — otherwise, your data and users could get confused with those belonging to someone else! Although that could cause some, er, interesting side effects, you’ll want to keep your data separate. :]

Your first step is to visit Parse.com and click Sign Up to create a new account.

Once the account is created, you will be asked to create your first app. Every app you use with the backend must be registered separately. In this case, call it “tutorialApp”; hundreds of apps may exist on Parse with identical names, but only one instance of that app will be registered to you.

Once your app has been created, you will be taken to the Dashboard where you have the option of viewing data about your app. There are some options in a series of buttons, a little like a UISegmentedControl, near the top of the screen, as shown in the following screenshot:

Here’s a guide to the options available at the top of the screen:

  • Overview: Here you can find statistical information about your app such as its traffic, the push notifications sent, or number of API calls made.
  • Data Browser: This is where you can see all the data that has been uploaded to your backend. You can also see the users, and you can manually manipulate the data; it’s very much a basic database editor.
  • Push Notifications: Use this section to send push notifications to all your users, or to send a push notification to a select group of them.
  • Settings: You can change the settings of your app, manage its security, and export your data from here.

The Parse Sample Application

In order to concentrate on the backend services in this tutorial, a base project is provided to make getting started easy. You can download it and add the Parse calls as you go through the tutorial. It is located on github.

To download it you can either download a ZIP from the github page, grab the excellent github client for Mac OS X, or use the following terminal command:

git clone https://github.com/toniomg/TutorialBase

Update 12/4/12: Scott Gardner has kindly provided a slightly refactored version of the base project here, with Modern Objective-C syntax and a few other improvements.

Open up the project in Xcode and build and run! The first thing you will see is a login screen. However, there is no back end yet to handle this, or the other parts of your app! You’ll create these functions shortly.

Before you proceed any further, have a look at the structure and flow of the app by opening MainStoryboard.storyboard.

The project is divided in 4 main views, each of them with its own ViewController and view in the storyboard:

  • Log In: Login screen with user and password text fields. There’s a Sign Up button to go to the Sign Up view in case you want to create a new user.
  • Sign Up: In this view, the user introduces the username and password to create a new account with the backend service.
  • Wall: This is the main screen of the app. Here, the user can see all of the images that other users have uploaded, the creation date and the comment associated with them.
  • Upload: In this view, the user can upload his own images to the wall and add a comment.

Take note of the segue lines showing the flow of the app, including the detour to Sign Up if necessary, as in the image below:

Preparing Parse Posthaste

The first step — quite naturally — is to configure your project to work with Parse!

Download the Parse framework from here:
https://parse.com/downloads/ios/parse-library/latest

Once you have downloaded it, unzip it and drag the folder Parse.framework to your Framework folder in the navigation menu of your Xcode project, and add this framework to your project. When prompted, check “Copy items…” and “Create groups…”.

The default action will be to add this framework to target “tutorialBase”, which is what you want. After that, add all frameworks to be sure that all of the following are included:

Screen Shot 2012 10 16 at 9 57 14 PM

Not sure how to do this? You’ll need to add each framework to the target’s Link Binary With Libraries section, under Build Phases, with the Project and the Target selected.

To add a library, click the ‘+’ to add each one. You can narrow down the choices by typing the first few characters of the name which will filter the results list, as in the screenshot below:

Screen Shot 2012 10 16 at 9 37 37 PM

If you miss anything, your code will compile but the linker will fail; the usual symptom is a bunch of weird names reported as not found. If that happens, go back and double check the libraries you’ve added.

Xcode may not put all libraries neatly away in the Frameworks folder in the Project navigator, so drag any that are left cluttering up your source files there manually.

The next step is to register your app with the backend when the app starts. Go to AppDelegate.m and add the following line:

#import <Parse/Parse.h>

Next, At the beginning of didFinishLaunchingWithOptions, add:

[Parse setApplicationId:AppID clientKey:clientKey];

As you can see from the errors that appear, Application ID and Client Key are required constants. Unfortunately, they’re empty right now — time to correct that! :]

In order to find the required API keys, go to the Parse Dashboard (1), select your app (2), and copy Application ID and Client Keys that you will find in the right column (3), as shown below:

You can put the keys directly in the setApplicationId method, as they are only used once. Once it’s done, it will look something like this, although your keys will differ:

 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Register our parse app with the service
    [Parse setApplicationId:@"UXuHVmNRX44rcczbv1NIIHHbazteYfQU4GAJ8EOS"
              clientKey:@"cqFwq5Vpb19VKPKSe1dOZJrjsQbytPzKa2bEdakx"];
 
    return YES;
}

Build and run the app! Check that everything compiles and runs without error. If so, then it means that your app is registered with the Parse backend and connected. You are ready to work with the service!

The next logical step is to create some sample objects! :]

Creating Some Sample Objects

Now that your project is configured and connected with Parse, take a minute to go over the following concepts about sending and retrieving objects from the backend.

You can create a new project for this, by following the steps that you used previously, or you can alternately use the AppDelegate in the base project.

In this example, you will use the class PFObject, which is a base class providing basic object manipulation methods. You can read more about PFObject here:

https://parse.com/docs/ios/api/Classes/PFObject.html

Every object you upload to Parse becomes an entry in the database scheme that you have defined for your app. Think of these objects as being somewhat like NSMutableDictionarys – you store data in them identified by key, then you can retrieve your data with those same keys later on.

In this example, you will upload an object called “Player”, with “Name” and “Score” as fields. So in your database, you will have a table called “Player” with all the objects uploaded with that name. You’ll see this with the example calls below.

Go to didFinishLaunchWithOptions: and right after connecting to the parse service, add these lines:

PFObject *player = [PFObject objectWithClassName:@"Player"];//1
[player setObject:@"John" forKey:@"Name"];
[player setObject:[NSNumber numberWithInt:1230] forKey:@"Score"];//2
[player save];//3
  1. In this line you create the object and give the object a class name of “Player”.
  2. Here you assign the values to the fields. Your player has a name of “John” and a score of “1230″.
  3. Here you save the object. This will send the object to the server in synchronous mode.

And that’s it! The best part is you don’t need to create a table in the Parse web interface itself – it will automatically create a schema for you based on what you upload :]

Build and run your app! If you put your keys into the code properly, and your app properly registered with the Parse service before the object is added, then everything should run without issue.

But where did your object go? Is it just out there floating in cyberspace?

To check that your object was saved correctly, go to your Parse dashboard, click on “Data Browser”, where you should see the object, as below:

This is the easiest way of saving an object. Congratulations, you’ve successfully communicated with the back end! :]

Going Asynchronous

But as you may have noticed, there was a warning message in the console. Your app is blocked until the object is completely sent, as this is a synchronous network operation! Not only can you not check the result of the call, your user is stuck waiting for it to complete with an unresponsive API.

That wouId give you an instant 1-star rating! :[ Of course, there is a way to fix both of these problems.

Comment out the previous code in didFinishLaunchWithOptions:; otherwise, your app will upload a new object every time you run. Add the following code instead:

     PFObject *anotherPlayer = [PFObject objectWithClassName:@"Player"];
    [anotherPlayer setObject:@"Jack" forKey:@"Name"];
    [anotherPlayer setObject:[NSNumber numberWithInt:840] forKey:@"Score"];
    [anotherPlayer saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
 
        if (succeeded){
            NSLog(@"Object Uploaded!");
        }
        else{
            NSString *errorString = [[error userInfo] objectForKey:@"error"];
            NSLog(@"Error: %@", errorString);
        }
 
    }];

As you can see here, you are using asynchronous mode to upload the object, and you are checking the result in a block. You should be familiar with blocks by now as they are becoming more and more common in iOS; even simple UIView animations are done in blocks now. Fortunately, there's a great tutorial site where you can refresh your memory about important language features like this - right here! :] Take a look at How To Use Blocks in iOS 5 Tutorial – Part 1.

Build and run your app!

Check the Parse Dashboard to see if your object was correctly sent to the server. The difference this time is that your app is not blocked while the object is being uploaded to the backend.

You should notice that the network activity indicator in the device (or simulator) appears and the login screen pops up while it spins. A short time later, once communications are complete, you will see the NSLog message appear in the console. This will prove to be really useful when uploading images, which take much longer to transfer.

Like before, go to the Data Browser and you will see the object transferred asynchronously alongside the first object which was transferred synchronously.

Hey Everyone, Come Back! – Retrieving Objects

Now, it’s time to retrieve the objects. For this purpose, Parse has the class PFQuery – unsurprisingly, it performs queries, as noted in the PFQuery documentation.

You will be coding a query for all the objects with a score greater than 1000 where “Name” is equal to “John”. As before, comment out the previous code or you will be uploading a new object every time. In its place, put the following code:

PFQuery *query = [PFQuery queryWithClassName:@"Player"]; //1
[query whereKey:@"Name" equalTo:@"John"];//2
[query whereKey:@"Score" greaterThan:[NSNumber numberWithInt:1000]]; //3
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {//4
    if (!error) {
        NSLog(@"Successfully retrieved: %@", objects);
    } else {
        NSString *errorString = [[error userInfo] objectForKey:@"error"];
        NSLog(@"Error: %@", errorString);
    }
}];
  1. Here you create they query object, the name will be the name of the table where you want to look.
  2. You are only going to get the objects which name is “John”…
  3. …and where the score is bigger than 1000
  4. Send the query, and print the result in a block.

Build and Run your app! Once again, the operation is asynchronous and does not stop your UI from appearing quickly — this is key to keeping your users happy. :] In the console, you should see all of the objects that match the query, as shown in the screenshot below:

Screen Shot 2012 11 10 at 9 48 56 PM

After this brief exploration of basic storage and query operations, you can continue working in the real project.

Go back to the base project if you were working on the other project, or comment out these lines in case you were working in the main project.

Sign on the Dotted Line — User Registration

The first step that your users will encounter in your app is to register themself as a user!

Open the class RegisterViewController.m in the base project. Add the Parse header as below:

#import <Parse/Parse.h>

As you can see, right now the view doesn’t do anything apart from being opened and closed. Your mission is to implement the functionality for user registration when the user touches the “Sign Up” button.

For this purpose, you can find this IBAction connected to that button:

//Sign Up Button pressed
-(IBAction)signUpUserPressed:(id)sender
{
    //TODO
    //If signup sucessful:
    //[self performSegueWithIdentifier:@"SignupSuccesful" sender:self];
}

As you can see, you will need to add the code that will register a user, and check if the registration was successful.

Replace the content of the above method with the following code:

//Sign Up Button pressed
-(IBAction)signUpUserPressed:(id)sender
{
    //1
    PFUser *user = [PFUser user];
    //2
    user.username = self.userRegisterTextField.text;
    user.password = self.passwordRegisterTextField.text;
    //3
    [user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
        if (!error) {
            //The registration was successful, go to the wall
            [self performSegueWithIdentifier:@"SignupSuccesful" sender:self];
 
        } else {
            //Something bad has occurred
            NSString *errorString = [[error userInfo] objectForKey:@"error"];
            UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
            [errorAlertView show];
        }
    }];
}

In the code above, the steps followed for creating a user are:

  1. Create a new object PFUser. This class will be used for login and register processes. It will store your authenticated user, so you can access the data for this user any time you want.
    You can find the documentation about the PFUser class here.
  2. Assign the username and password to the user object from the TextFields in the view.
  3. Call the method that will register the user in background, and check the response in a block. There’s two possible responses here: the response is ok; and your user is created and logged, so move to the wall view. Or, there was an error, and you can show the user a description of the error.

Build and run the app and check for errors!

To check the user registration process, run the app, and at the Log In screen press the Sign Up button. You should see the following:

Enter the name and password of the new user, and press the Sign Up button. If everything went well, and no errors were received by the registration process, the app will move to the wall view.

Great! But you still need to verify that your new user actually was saved in your schema! You can check that your user was successfully created by looking in the Parse data browser of the backend project, as below:

Congratulations! Your first user was created! Now it’s time to let that user log in and get busy with the backend! :]

Little Pig, Let Me In — Logging In

In this section, you’ll learn how to login with the user you created in the previous section.

Open the LoginViewController.m class, and add the following:

#import <Parse/Parse.h>

Then take a look at the method below:

//Login button pressed
-(IBAction)logInPressed:(id)sender
{
    //If user logged succesful:
    //[self performSegueWithIdentifier:@"LoginSuccesful" sender:self];
 
}

As you can see, this part is very similar to the registration process! You are going to use the PFUser class again, but this time you’ll be using it to log in. Replace the stubbed-out content of the above method with this code:

//Login button pressed
-(IBAction)logInPressed:(id)sender
{
    [PFUser logInWithUsernameInBackground:self.userTextField.text password:self.passwordTextField.text block:^(PFUser *user, NSError *error) {
        if (user) {
            //Open the wall
             [self performSegueWithIdentifier:@"LoginSuccesful" sender:self];
        } else {
            //Something bad has ocurred
            NSString *errorString = [[error userInfo] objectForKey:@"error"];
            UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
            [errorAlertView show];
        }
    }];
}

As you can see the process is quite simple, and very similar to the registration process.

Build and run the app! (Isn’t it great when you can see this much progress this quickly?) :]

As soon as you launch the app, you will see the login view below:

Try to log in with the same user you created in the previous section. If everything goes well, your app should move to the wall view.

Just Another Brick In The Wall

Both previous actions (register and login) will move the app to the Wall View. In this view, you
are going to see the pictures that all the users of your backend service have uploaded, with comments attached.

But before you can see anything, something has to be uploaded! :]

Parse makes it easy to upload files. Take a look at UploadImageViewController.m which is where you’ll do the work to upload files.

A logged-in user can tap the Upload button on the Wall view; it’s the rightBarButtonItem. Walking through UploadImageViewController.m, the process for uploading a file is discussed below.

IBAction selectPicturePressed: is triggered by the user tapping the Upload button. The system image picker is presented to allow the user to choose an image from the photo library, as below:

-(IBAction)selectPicturePressed:(id)sender
{
    //Open a UIImagePickerController to select the picture
    UIImagePickerController *imgPicker = [[UIImagePickerController alloc] init];
    imgPicker.delegate = self;
    imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
 
    [self.navigationController presentModalViewController:imgPicker animated:YES];
}

Once the picture is selected, the image picker is dismissed and the picture is shown in the UIImageView of the main screen, as follows:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo 
{
    [picker dismissModalViewControllerAnimated:YES];
    //Place the image in the imageview
    self.imgToUpload.image = img;
}

The user can enter text in the UITextfield commentTextField that will be attached to the picture. If text is entered here it will appear as a comment on the image – it’s optional.

This is already done for you! Now it’s time to add the code that completes the implementation of the sendPressed method. This is the action linked to the button on the Navigation Toolbar that will send your picture and comment to the server.

The process is divided into two parts. First, upload the image using a PFFile object; second, attach it to a PFObject and upload it to the server.

First, add the following header to start of the UploadImageViewController.m file:

#import <Parse/Parse.h>

Right before the end of -(IBAction)sendPressed:(id)sender add the following code:

  //Upload a new picture
    //1
    PFFile *file = [PFFile fileWithName:@"img" data:pictureData];
    [file saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
 
        if (succeeded){
            //2
            //Add the image to the object, and add the comment and the user
            PFObject *imageObject = [PFObject objectWithClassName:@"WallImageObject"];
            [imageObject setObject:file forKey:@"image"];
            [imageObject setObject:[PFUser currentUser].username forKey:@"user"];
            [imageObject setObject:self.commentTextField.text forKey:@"comment"];
            //3
            [imageObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
                //4
                if (succeeded){
                    //Go back to the wall
                    [self.navigationController popViewControllerAnimated:YES];
                }
                else{
                    NSString *errorString = [[error userInfo] objectForKey:@"error"];
                    UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
                    [errorAlertView show];
                }
            }];
        }
        else{
            //5
            NSString *errorString = [[error userInfo] objectForKey:@"error"];
            UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
            [errorAlertView show];
        }        
    } progressBlock:^(int percentDone) {
        NSLog(@"Uploaded: %d %%", percentDone);
    }];

The explanation of the code above is as follows:

  1. Create the PFFile object with the data of the image, and save it in the background. You can check the progress of the upload at the end of the block.
  2. If successful, create the PFObject that will contain the image and the data, and add the file, the username, and the comment to the object.
  3. Save it in the background.
  4. If successful, go back to the Wall.
  5. If not, inform the user.

Build and run your app! Login with the user you created previously, and go to the upload screen, which is accessed via the top right button in the Wall Screen:

Press Select Picture to select a picture from your gallery. When it’s selected, write a comment if you like, and press the Send button.

You can follow the percentage of the upload in the console – the progress block of the upload operation updates with the percentage complete status of the upload. Here, it’s shown in the debug console, but your finished app would more correctly show a progress bar to the user.

Now go to the Data Browser and view the object in your new table called “WallImageObject”. Hooray! But wait — you can’t see it in the app yet!

Now’s a perfect time to implement the picture retrieval process! :]

Hang Those Pictures on Your Wall

The WallPicturesViewController.m view will show all of the pictures that your users have uploaded to the server.

Can you guess the first thing to be added to WallPicturesViewController.m? :] Yup, it’s the code below:

#import <Parse/Parse.h>

The method getWallImages will be called in the load of the view to retrieve all the objects. As you can see, it’s empty now. Replace the content of getWallImages with the following code:

-(void)getWallImages
{
    //Prepare the query to get all the images in descending order
    //1
    PFQuery *query = [PFQuery queryWithClassName:@"WallImageObject"];
//2
    [query orderByDescending:@"createdAt"];
    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        //3 
        if (!error) {
            //Everything was correct, put the new objects and load the wall
            self.wallObjectsArray = nil;
            self.wallObjectsArray = [[NSArray alloc] initWithArray:objects];
            [self loadWallViews];
 
        } else {
 
            //4
            NSString *errorString = [[error userInfo] objectForKey:@"error"];
            UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
            [errorAlertView show];
        }
    }];
 
}

Here’s what the above code is doing:

  1. Create a simple query with the name of the object you want to retrieve.
  2. Put the objects in descending order using the creation date.
  3. Find the object that matches the query. In this case, show all the objects of the type WallImageObject. If everything went fine, replace the content of the instance variable wallObjectArray with the downloaded content.
  4. If not, inform the user of an error.

Once the objects are downloaded, it’s time to show them on the wall! Head to the loadWallImages method and implement it as follows:

-(void)loadWallViews
{
    //Clean the scroll view
    for (id viewToRemove in [self.wallScroll subviews]){
 
        if ([viewToRemove isMemberOfClass:[UIView class]])
            [viewToRemove removeFromSuperview];
    }
 
    //For every wall element, put a view in the scroll
    int originY = 10;
 
    for (PFObject *wallObject in self.wallObjectsArray){
 
        //1
        //Build the view with the image and the comments
        UIView *wallImageView = [[UIView alloc] initWithFrame:CGRectMake(10, originY, self.view.frame.size.width - 20 , 300)];
 
        //2
        //Add the image
        PFFile *image = (PFFile *)[wallObject objectForKey:@"image"];
        UIImageView *userImage = [[UIImageView alloc] initWithImage:[UIImage imageWithData:image.getData]];
        userImage.frame = CGRectMake(0, 0, wallImageView.frame.size.width, 200);
        [wallImageView addSubview:userImage];
 
        //3
        //Add the info label (User and creation date)
        NSDate *creationDate = wallObject.createdAt;
        NSDateFormatter *df = [[NSDateFormatter alloc] init];
        [df setDateFormat:@"HH:mm dd/MM yyyy"];
        //4
        UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 210, wallImageView.frame.size.width,15)];
        infoLabel.text = [NSString stringWithFormat:@"Uploaded by: %@, %@", [wallObject objectForKey:@"user"], [df stringFromDate:creationDate]];
        infoLabel.font = [UIFont fontWithName:@"Arial-ItalicMT" size:9];
        infoLabel.textColor = [UIColor whiteColor];
        infoLabel.backgroundColor = [UIColor clearColor];
        [wallImageView addSubview:infoLabel];
 
        //5
        //Add the comment
        UILabel *commentLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 240, wallImageView.frame.size.width, 15)];
        commentLabel.text = [wallObject objectForKey:@"comment"];
        commentLabel.font = [UIFont fontWithName:@"ArialMT" size:13];
        commentLabel.textColor = [UIColor whiteColor];
        commentLabel.backgroundColor = [UIColor clearColor];
        [wallImageView addSubview:commentLabel];
 
        //6
        [self.wallScroll addSubview:wallImageView];
 
 
        originY = originY + wallImageView.frame.size.width + 20;
 
    }
 
    //7
    //Set the bounds of the scroll
    self.wallScroll.contentSize = CGSizeMake(self.wallScroll.frame.size.width, originY);
 
}

The first step is to clean the scrollView of any other UIView that may be there, for example, if you reload the screen. Then you use fast enumeration to go through the whole array of objects. Every element in the array will be cast to a PFObject, with one of the object values being a PFFile.

For every object in the array:

  1. Build the view that will contain the image and the comment
  2. Get the image object (cast it to PFFile) and put it in a UIImageView (the image in the PFObject will be a NSData type).
  3. Get the creation date of the object
  4. Get the user that uploaded the image and put it in a label with the creation date.
  5. Add a label with the comment.
  6. Add it to the scroll view.

Once every object has been parsed, then set the bounds of the scroll view depending on the size and position of the last view.

Build and run your app! If everything was implemented correctly, you should see the image and the comment you previously uploaded. Take some time now to play with the app, uploading some more images and comments, and seeing them appear on your wall!

Feels good, doesn’t it? :]

Time to Close up Shop — Logging Out

The last part of the tutorial is to allow the user to logout. For that, simply add the following code in WallPicturesViewController.m, inside -(IBAction)logoutPressed:(id)sender:

-(IBAction)logoutPressed:(id)sender
{
    [PFUser logOut];
    [self.navigationController popViewControllerAnimated:YES];
}

Build and run, and you’re done! :]

Where To Go From Here?

Here is the complete example project you developed in the above tutorial.

Hopefully you have seen how easy it is to upload and download objects based on PFObject and how to work with PFUsers in Parse!

At this point, you’re likely inspired to add some backend functionality to a project that could benefit from it; or perhaps a cloud app you thought was going to be too hard is now within reach! :]

I hope to see some apps made from you with Parse in the future. If you have any questions or comments, please join the forum discussion below! :]


This is a post by Tutorial Team Member Antonio Martínez, a mobile software developer currently working as an iOS Developer in London.

User Comments

46 Comments

[ 1 , 2 , 3 , 4 ]
  • Great tutorial. Got it working...Thanks Antonio Martinez.
    stanco2rhyme
[ 1 , 2 , 3 , 4 ]

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in September: iOS 8 App Extensions!

Sign Up - September

RWDevCon Conference?

We are considering having an official raywenderlich.com conference called RWDevCon in DC in early 2015.

The conference would be focused on high quality Swift/iOS 8 technical content, and connecting as a community.

Would this be something you'd be interested in?

    Loading ... Loading ...

Our Books

Our Team

Tutorial Team

  • Tammy Coron
  • Kirill Muzykov

... 49 total!

Update Team

Editorial Team

... 23 total!

Code Team

  • Orta Therox

... 3 total!

Translation Team

  • Heejun Han
  • Jesus Guerra
  • David Xie

... 33 total!

Subject Matter Experts

... 4 total!