How To Easily Create A Web Backend for Your Apps 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 […] By .

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

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? :]