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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Parse Tutorial: Getting Started with Web Backends
35 mins
Showing Pictures on the Wall
Open WallPicturesViewController.swift. This view will show all of your users uploaded pictures.
When the view loads, it calls getWallImages()
to retrieve all the objects. As you can see, it’s empty now.
Before you can make that work, you’ll need to add some code to place the images on the wall once you’ve retrieved them. To that end, add loadWallViews(_:)
as follows:
func loadWallViews(objects: [WallPost]) {
cleanWall()
var originY: CGFloat = 0
for wallPost in objects {
//1
let wallView = UIView(frame: CGRect(x: 0, y: originY,
width: self.wallScroll.frame.size.width, height: 270))
//2
wallPost.image.getDataInBackgroundWithBlock { data, error in
if let data = data, image = UIImage(data: data) {
//3
//Add the image
let imageView = UIImageView(image: image)
imageView.frame = CGRect(x: 10, y: 10, width: wallView.frame.size.width - 20, height: 200)
imageView.contentMode = UIViewContentMode.ScaleAspectFit
wallView.addSubview(imageView)
//4
//Add the info label (User and creation date)
let creationDate = wallPost.createdAt
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "HH:mm dd/MM yyyy"
let infoLabel = UILabel(frame: CGRect(x: 10, y: 220, width: 0, height: 0))
let dateString = dateFormatter.stringFromDate(creationDate!)
if let username = wallPost.user.username {
infoLabel.text = "Uploaded by: \(username), \(dateString)"
} else {
infoLabel.text = "Uploaded by anonymous: , \(dateString)"
}
infoLabel.text = "Uploaded by: \(wallPost.user.username), \(dateString)"
infoLabel.font = UIFont(name: "HelveticaNeue", size: 12)
infoLabel.textColor = UIColor.whiteColor()
infoLabel.backgroundColor = UIColor.clearColor()
infoLabel.sizeToFit()
wallView.addSubview(infoLabel)
//5
//Add the comment label (User and creation date)
let commentLabel = UILabel(frame: CGRect(x: 10, y: CGRectGetMaxY(infoLabel.frame)+5, width:0, height: 0))
commentLabel.text = wallPost.comment
commentLabel.font = UIFont(name: "HelveticaNeue", size: 16)
commentLabel.textColor = UIColor.whiteColor()
commentLabel.backgroundColor = UIColor.clearColor()
commentLabel.sizeToFit()
wallView.addSubview(commentLabel)
}
}
//6
wallScroll.addSubview(wallView)
originY += 270
}
//7
wallScroll.contentSize.height = CGFloat(originY)
}
The first step is to clean the scroll view of any other UIView
objects that may be there, for example, if you reload the screen. Then you use fast enumeration to go through the whole array of objects. For every object in the array:
- Create a view to display the image and post details.
- Download the image data.
- Add the image view to the wall view
- Get the user that uploaded the image, and put it in a label with the creation date.
- Add a label with the comment.
- Add it to the scroll view and increment the next post’s position.
- Set the ScrollView’s content size.
Now, replace the content of getWallImages()
with the following code:
func getWallImages() {
//1
let query = WallPost.query()!
query.findObjectsInBackgroundWithBlock { objects, error in
if error == nil {
//2
if let objects = objects as? [WallPost] {
self.loadWallViews(objects)
}
} else if let error = error {
//3
self.showErrorView(error)
}
}
}
Here’s what this code is doing:
- Create a simple query to retrieve
WallPost
objects, and sorts the query by creation date as we defined earlier in WallPost.swift. - Find the object that matches the query. In this case, show all the objects of the type
WallPost
. If everything went fine, load the posts to the wall. - If there was an error, then inform the user.
Build and run! 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? :]
ParseUI
As noted earlier there is another way to present the saved images. That’s the approach you will implement next.
In the previous section you presented the images in a simple UIScrollView
, and calculated their sizes yourself. You may have thought that this job would be better done with a UITableView
. Well, the smart people at Parse thought the same thing, so they wrote ParseUI.framework and filled it with some very handy objects to display Parse specific UI.
You’re going to focus on these three:
-
PFQueryTableViewController: This
UITableViewController
subclass makes is as simple as it can be to execute aPFQuery
and display the result in a table. -
PFTableViewCell: A
UITableViewCell
subclass to go along with thePFQueryTableViewController
object. -
PFImageView: This
UIImageView
subclass manages downloading and displaying images stored on Parse’s server.
Now, open WallPicturesTableViewController.swift and change its superclass from UITableViewController
to PFQueryTableViewController
.
Similarly, modify WallPostTableViewCell to make it a subclass of PFTableViewCell
instead of UITableViewCell
. In addition change the postImage
property to be of type PFImageView
instead of UIImageView
.
Before you add code, you need to make some changes to your storyboard. Open Main.storyboard and locate the WallTableView scene:
Open the Attributes Inspector and you’ll see you have an option to set parameters that are specific to PFQueryTableViewController
:
These parameters let you choose the object type to fetch and show in the table, and also let you define the the table’s behavior by adding pull to refresh, pagination, and a loading view. When using a simple UITableView
to present the results, you could even set the PFObject
keys you want shown in the table, without needing to fill it in code. Under Parse Class enter WallPost.
Now go back to WallPicturesTableViewController.swift and add the following methods:
override func viewWillAppear(animated: Bool) {
loadObjects()
}
override func queryForTable() -> PFQuery {
let query = WallPost.query()
return query!
}
Every time the view appears, you want to reload the query and the table view. To specify which query to run, you override queryForTable()
to return a query for a WallPost
.
Finally, add the following table view delegate method to the class:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject!) -> PFTableViewCell? {
// 1
let cell = tableView.dequeueReusableCellWithIdentifier("WallPostCell", forIndexPath: indexPath) as! WallPostTableViewCell
// 2
let wallPost = object as! WallPost
// 3
cell.postImage.file = wallPost.image
cell.postImage.loadInBackground(nil) { percent in
cell.progressView.progress = Float(percent)*0.01
println("\(percent)%")
}
// 4
let creationDate = wallPost.createdAt
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "HH:mm dd/MM yyyy"
let dateString = dateFormatter.stringFromDate(creationDate!)
if let username = wallPost.user.username {
cell.createdByLabel.text = "Uploaded by: \(username), \(dateString)"
} else {
cell.createdByLabel.text = "Uploaded by anonymous: , \(dateString)"
}
cell.createdByLabel.text = "Uploaded by: \(wallPost.user.username), \(dateString)"
cell.commentLabel.text = wallPost.comment
return cell
}
This method replaces the UITableView
data source method tableView(_:cellForRowAtIndexPath:)
with a more suitable form. You get the returned PFObject
as a parameter, without the need search it in a results array using and index path.
Let’s go over what this code does:
- Dequeue a cell from the table view, and cast it to a WallPostTableViewCell.
- Cast the given
PFObject
to a WallPost object - Download the post image using
PFImageView
‘sloadInBackground
method. In the completion closure you track the download’s progress. Here you fill aUIProgressBar
as the image downloads. - Add the creation date, the user’s name and the comment to the cell.
Before you can run this code, there’s one last thing you need to do. Go to LoginViewController.swift, and inside logInPressed(_:)
replace the segues name from scrollViewWallSegue
to tableViewWallSegue
. Do the same in RegisterViewController.swift.
Build and run you code, and you’ll see the wall posts presented in a table view with a nice progress bar filling up as the images are downloading.