Parse Tutorial: Getting Started with Web Backends

Get started with Parse, and learn how to set up your iOS app with a backend that lets you store user accounts, posts, and attachments! By Ron Kliffer.

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

Logging In

Open the LoginViewController.swift class, and take a look at the method below:

@IBAction func logInPressed(sender: AnyObject) {
  //If user logged succesful:
  performSegueWithIdentifier(scrollViewWallSegue, sender: nil)
}

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

@IBAction func logInPressed(sender: AnyObject) {
  PFUser.logInWithUsernameInBackground(userTextField.text, password: passwordTextField.text) { user, error in
    if user != nil {
      self.performSegueWithIdentifier(self.scrollViewWallSegue, sender: nil)
    } else if let error = error {
      self.showErrorView(error)
    }
  }
}

As you can see, the process is quite simple and very similar to the registration process. Rather than just perform the segue, you first check that the username and password match what’s in the data store.

Build and run the app and you’ll see the login view below:

Initial Screenshot

Try to log in with the same user you created in the previous section. If all goes well, your app will move to the wall view. As a sanity check, try logging in with a bad username or password to see the error message.

Posting to the Wall

Both previous actions (register and log in) 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 uploaded, with their comments attached.

But before you can see anything, you’ll have to upload something! :]

Parse makes it easy to upload files. Open UploadImageViewController.swift, which is where you’ll do the work to upload files.

A logged-in user can tap the “Upload” button on the Wall view to take them to the upload screen shown below.

Initial Screenshot

From here, the user can enter an optional comment and tap “Select Picture” to select something from the library to upload using the standard image picker.

All this is already implemented in the starter app – now it’s time to add the code that completes the implementation of sendPressed(_:). This is the action – linked to the “Send” button on the Navigation Toolbar – that sends your picture and comment to the server.

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

As you saw earlier in the tutorial, you can add and retrieve various fields to a PFObject using setKey and objectForKey. But if you have a specific type of object you use in your app, say like a wall post, wouldn’t it be nice to give it it’s own subclass with relevant properties? You will next see how you can make that happen.

Custom Parse Objects

Open the WallPost.swift file from the Model group in the project navigator. Right now, you’ll see a simple NSObject subclass with an empty implementation. The first thing you’ll need to do is make it a PFObject subclass as follows:

class WallPost: PFObject {  
}

You also want WallPost to conform to the PFSubclassing protocol.

The PFSubclassing protocol declares a few required methods for subclassing a PFObject. The PFObject+Subclass.h Obj-C category implements these methods, and you can override them.

You will do this by adding the extension shown below right after the WallPost class. This extension contains two required protocol methods.

extension WallPost: PFSubclassing {
  // Table view delegate methods here
  //1
  class func parseClassName() -> String {
    return "WallPost"
  }
  
  //2
  override class func initialize() {
    var onceToken: dispatch_once_t = 0
    dispatch_once(&onceToken) {
      self.registerSubclass()
    }
  }
}
  1. Set the name of the class as seen in the backend database.
  2. Let Parse know that you intend to use this subclass for all objects with class type WallPost. You want to do this only once, so you’re using dispatch_once_t to make sure of that.

Next, add three properties to the WallPost class, as follows:

@NSManaged var image: PFFile
@NSManaged var user: PFUser
@NSManaged var comment: String?

Here you’re adding a PFFile property to hold the posted image, a PFUser property to hold the user who uploaded the image, and an optional String property for the post comment.

You’re using @NSManaged here because deep down, PFObject properties are just a set of key-value parameters. This way, when you set the value of each property, it will automatically be written as a key-value pair.

Another thing you want to do is define the PFQuery object that this subclass returns when calling query(). Add the following to the WallPost class in WallPost.swift:

override class func query() -> PFQuery? {
  //1
  let query = PFQuery(className: WallPost.parseClassName())
  //2 
  query.includeKey("user") 
  //3
  query.orderByDescending("createdAt")
  return query
}

Here’s what’s going on in this method:

  1. Create a PFQuery object for the WallPost class.
  2. Request that this query will return the full user details. Without this line of code, the query will just return the object reference of the user without its details.
  3. Sort the results by their creation date.

The last thing to do in WallPost.swift, before moving on, is writing an initializer. Add the following to the WallPost class:

init(image: PFFile, user: PFUser, comment: String?) {
  super.init()
        
  self.image = image
  self.user = user
  self.comment = comment
}
    
override init() {
  super.init()
}

This is a simple initializer to create a WallPost object – either with starter values or without.

Now that you have the WallPost class done, you’ll go back to uploading the images to the Parse server.
Open UploadImageViewController.swift, and right before the end of sendPressed(_:) add the following code:

  
//Upload a new picture
//1
let file = PFFile(name: "image", data: pictureData)
file.saveInBackgroundWithBlock({ (succeeded, error) -> Void in
  if succeeded {
    //2
    self.saveWallPost(file)
  } else if let error = error {
    //3
    self.showErrorView(error)
  }
}, progressBlock: { percent in
   //4
   println("Uploaded: \(percent)%")
})

Here’s what’s going on here:

  1. Create the PFFile object with the data of the image, and save it in the background.
  2. If successful, save the PostWall object with the file you just successfully uploaded.
  3. If not, inform the user.
  4. When saving a file, Parse let’s you track the progress with this progress block (closure in swift). Here you just write the progress to the console.

Next up is saveWallPost(_:); add the following to the WallPost class:

func saveWallPost(file: PFFile)
{
  //1
  let wallPost = WallPost(image: file, user: PFUser.currentUser()!, comment: self.commentTextField.text)
  //2      
  wallPost.saveInBackgroundWithBlock{ succeeded, error in
    if succeeded {
      //3
      self.navigationController?.popViewControllerAnimated(true)
    } else {
      //4
      if let errorMessage = error?.userInfo?["error"] as? String {
        self.showErrorView(error!)
      }
    }
  }
}

This method does the following steps:

  1. Create the WallPost object with the uploaded image, the current logged in user, and the comment.
  2. Save to WallPost in the background.
  3. If successful, go back to the wall.
  4. If not, inform the user.

Build and run your app. Log in with the user you created previously, and go to the upload screen 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 Core Data Browser and view the object in your new table called WallPost. Hooray! But wait — you can’t see it in the app yet!

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