Parse Tutorial: Network Backend Basics

Parse Tutorial: Network Backend Basics

[[141390]]

This tutorial has been updated for Swift, iOS 8.3, Xcode 6.3, and the latest Parse SDK (version 1.7.1).

Network backend support can add many new features to your App: data synchronization, social sharing, and cloud storage can all be handled with ease. As a professional iOS developer, how can you add server-side support to your App?

In this Parse tutorial, you will learn how to create an App that uses Parse backend support. The main function of this App is photo sharing, including user login, photo upload and photo wall functions. In order to allow you to focus on the implementation of aParse, this project pre-includes part of the user interface, but does not include the functions of uploading and displaying photos. You will add Parse services step by step to complete a complete App.

Are you ready to create apps with ease? Okay, let’s get started with Parse.

Preparation

Before starting the App development work, the first step is to create a Parse App in the background. Every developer and every App needs a unique identifier, otherwise your data and users will be mixed up with others.

Visit Parse.com, click “Get started for free”, then click Sign up to create a new account.

After creating your account, Parse will ask you if you want to create your first app. You must register a separate backend app for each iOS app. In this tutorial, we call it "Tutorial App". There may be many apps on Parse, each with a different identifier, but right now there is only one app instance that belongs to you.

After creating the app, you will see a welcome screen with many options to help you add Parse functionality. These options will have templates available for download, but they are not needed for this tutorial. There are several option buttons at the top of the page, as shown below:

Here is a description of the options:

  • Core: Here you can see all the data you have previously uploaded. You can also see the users and manage this data manually.
  • Analytics: Here you can view statistics about the app, such as data traffic, push notifications sent, and the number of API calls. You can also add custom events.
  • Push: Use this feature to send push notifications to any group of users.
  • Settings: Here you can see all your API keys. In addition, you can modify your app's settings, manage security options, and export data.
  • Docs: Here you can find tutorials, sample projects, API documentation, and learn all about how to extend your app’s functionality using Parse.

Parse Example Program

To focus on the backend service, this tutorial includes a starter project that you can download directly and then follow the tutorial steps to add Parse calls.

Open the project in Xcode and run it. First, you will see a login page. But the buttons on this page don't do anything yet. You will learn how to create these functions later.

Before we get started, open the Main.storyboard file to take a look at the structure and flow of the app.

The project contains the following 4 main views:

  • Login: The login screen has username and password text boxes, and a Register button to create a new user.
  • Register: This interface is used to enter the user name and password to create a new user in the background.
  • Image Wall: This is the main view of the app. Here you can see all other user uploaded images, creation date and photo comments.
  • Upload: In this view, users can upload their own pictures to the photo library and add a note (optional).

Each view has a corresponding UIViewController in the Storyboard, but you’ll notice that the “Photo Wall” view has two representations. This is because you’ll see two ways to implement this view using Parse.

Parse Fast Prepare

The first step, of course, is to configure your project to use Parse.

Download the Parse iOS SDK using the following link: https://parse.com/downloads/ios/parse-library/latest

After downloading, unzip and drag the three framework files in the frameworks folder into your project. When the prompt box appears, select "Copy items..." and "Create groups...". Xcode will add these frameworks to the "ParseTutorial" target by default, no additional configuration is required.

  • Parse.framework: This is the main framework, which contains all the background functions of Parse.
  • Bolts.framework: This framework is a collection of low-level libraries that make many tasks easy and fast.
  • ParseUI.framework: This framework contains some very convenient UI elements that can interact directly with Parse objects. You will use this framework to create a photo wall.

Note: When adding Parse to an existing project, you will also need to add some of the Parse framework’s dependencies, such as CoreGraphics and SystemConfiguration. Our starter project already includes these, and you can find the complete steps in the "Parse Quick Start Guide".

The Parse SDK is implemented in Objective-C, and you will use Swift to create your app. To use the Parse Obj-C SDK in a Swift program, you need an Objective-C bridging header file.

The easiest way to create a bridging header file is to add any Objective-C file to your project. Xcode will automatically create the header file for you.

In Xcode, select File\New\File... and choose the iOS\Source\Objective-C file template. Name it whatever you want (we will delete the file later), then save it. When you save this file, Xcode will provide an Objective-C bridging header file. As shown in the figure:

After clicking Yes, Xcode will create a bridging header file and add it to your project. The Objective-C file is no longer needed and can be deleted directly.

Open the newly created "ParseTutorial-Bridging-Header.h" file and add the following content to the bottom of the file:

  1. #import #import #import  

After adding, these three frameworks can be used in Swift code.

Next, you need to get the API key for our app from the Parse website. Open your app's Settings interface on the Parse Dashboard and select the Keys button on the left panel. Make a note of the Application ID and Client Key.

Next, open the AppDelegate.swift file and locate application(_:didFinishLaunchingWithOptions:). Add the following to the beginning of the method:

  1. Parse.setApplicationId( "--AppID Goes Here--" , clientKey: "--ClientKey Goes Here--" )

Of course, you need to fill in the real ID and Key you wrote down earlier in the AppID and clientKey positions.

Build and run the app. If there are no errors, it means the app has been registered and connected to the Parse backend. You can now call Parse related services.

In the next step, we'll create some sample objects.

#p#

Creating a Sample Object

Each Parse object uploaded becomes an entry point to the database structure. You can think of these objects as dictionaries - data is stored in advance with keywords, and then you can get the object by keyword.

In this example, you will upload an object called "Player" with two fields "Name" and "Score". Therefore, in the database, there will be a table called "Player" containing all objects uploaded with the name "Player". You will see an example of this later.

Open AppDelegate.swift and add the following code to application(_:didFinishLaunchingWithOptions:) before the return true statement.

  1. let player = PFObject(className: "Player" )
  2. player.setObject( "John" , forKey: "Name" )
  3. player.setObject( 1230 , forKey: "Score" )
  4. player.saveInBackgroundWithBlock { (succeeded, error) -> Void in
  5. if succeeded {
  6. println( "Object Uploaded" )
  7. } else {
  8. println( "Error: \(error) \(error.userInfo!)" )
  9. }
  10. }

As you can see, the code that uploads the object is asynchronous and you will check the result in the closure.

PFObject is a base class in Parse, which provides some basic object operation methods. The biggest benefit is that you don't need to create a table on the Parse website, Parse will create the table structure based on the object you submit.

Build and run. If you placed the API key correctly and the app registered with the Parse service correctly, the app should run fine. Otherwise, you will receive an error message.

Wait, where did your partner go? Just floating around in cyberspace?

To view the objects you saved correctly, just open the Parse dashboard and click Core. You should see the objects as shown below:

Congratulations, you have successfully interacted with the network backend.

Note: If you run the app on the iOS Simulator and see an error message such as "The network connection was lost", try restarting the simulator. This method can also be used to try other network errors.

If you have received the "Object Uploaded" message but do not see data on the Dashboard, please click the "Refresh" button in the upper right corner to refresh the Dashboard page.

Before moving on to the next step, create another data item. Set the name to "John" and the score to 810. Now you have two data items, both with the name John, but different scores. Add a third data item with the name "Sally" and the score to 2400.

Get Object

Now, let’s try to fetch an object. Parse has the PFQuery class to support this. It can perform data queries, and you can read more about it in the PFQuery documentation.

Let's implement getting objects that meet the following conditions:

score is greater than 1000, and name is equal to "John". Comment out (or delete) the previous code, otherwise a new object will be uploaded each time it is run. Then place the following code:

  1. // 1  
  2. let query = PFQuery(className: "Player" )
  3. // 2  
  4. query.whereKey( "Name" , equalTo: "John" )
  5. query.whereKey( "Score" , greaterThan: 1000 )
  6. // 3  
  7. query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
  8. if error == nil {
  9. println( "Successfully retrieved: \(objects)" )
  10. } else {
  11. println( "Error: \(error) \(error.userInfo!)" )
  12. }
  13. }
  1. Here we create an object for data request, and the class name is the table name.
  2. Through the whereKey method, specify that only objects that meet the conditions (name is John, score is greater than 1000) are obtained.
  3. Send the request and then print the result in the closure.

Build and run the app again. The data request is asynchronous, so it won’t slow down the UI display—which makes your users happier. In the console, you should see all the objects that meet the criteria, as shown below:

Now that we have explored the basic operations for storing and retrieving data, let's apply them in a real project.

Remember to comment out the code we just wrote in application(_:didFinishLaunchingWithOptions:) first.

User Registration

First, users will register an account using our app.

Open RegisterViewController.swift. Currently, this interface can’t do anything. Our task is to implement the function after clicking the “Sign Up” button.

Locate the signUpPressed(_:) method and replace the code with the following:

  1. @IBAction func signUpPressed(sender: AnyObject) {
  2. //1  
  3. let user = PFUser()
  4.    
  5. //2  
  6. user.username = userTextField.text
  7. user.password = passwordTextField.text
  8.    
  9. //3  
  10. user.signUpInBackgroundWithBlock { succeeded, error in
  11. if (succeeded) {
  12. //The registration was successful, go to the wall  
  13. self.performSegueWithIdentifier(self.scrollViewWallSegue, sender: nil)
  14. } else   if let error = error {
  15. //Something bad has occurred  
  16. self.showErrorView(error)
  17. }
  18. }
  19. }

In the above code, create a user according to the following steps:

  1. Create a PFUser object and assign it to user. You will use this object to complete the login and registration process. It will store your authenticated user information so that you can access the user's data. You can access the PFUser documentation through this link: http://www.parse.com/docs/ios/api/Classes/PFUser.html
  2. Get the contents of the username and password text boxes on the interface, and assign values ​​to the corresponding fields in the user object.
  3. The background calls the registered method and then checks the return value. There may be two results: a normal return indicates that the user has been successfully created and logged in as the user; if there is an error, the creation failed. If the creation is successful, it will jump directly to the photo wall interface, otherwise an error prompt will be given.

Build and run the app to see if there are any errors. In the Log In interface, click the Sign Up button and you will see the following interface:

[[141393]]

Enter your username and password, click the Sign Up button, and if everything goes well you will be redirected to the photo wall interface.

That’s good, but to be on the safe side, let’s verify whether the new user has actually been created successfully in the table: Open the User option in the Dashboard, as shown below:

Congratulations! You have created your first user. Now let's log in with this user and do some interesting things.

Log in

Open the LoginViewController.swift class and find the following method:

  1. @IBAction func logInPressed(sender: AnyObject) {
  2. //If user logged successful:  
  3. performSegueWithIdentifier(scrollViewWallSegue, sender: nil)
  4. }

As you can see, this method is very similar to the one in the registration process. We are still using PFUser here, but for login. Replace the code in the method:

  1. @IBAction func logInPressed(sender: AnyObject) {
  2. PFUser.logInWithUsernameInBackground(userTextField.text, password: passwordTextField.text) { user, error in
  3. if user != nil {
  4. self.performSegueWithIdentifier(self.scrollViewWallSegue, sender: nil)
  5. } else   if let error = error {
  6. self.showErrorView(error)
  7. }
  8. }
  9. }

The process is very simple. Before jumping to the next screen, we first check whether the username and password match the records in the database.

Build and run the program, the effect is as follows:

Try to log in with the user we created. If everything is normal, the app will jump to the photo wall interface. To be on the safe side, you can try to log in with an incorrect username or password to see if there is an error code displayed.

#p#

Post photos to the photo wall

The previous registration and login operations will jump to the photo wall view. In this view, you will see all the pictures and comments uploaded by users.

Before that, we have to upload some pictures.

Uploading files with Parse is simple. Open UploadImageViewController.swift, where we will implement the upload functionality.

All users who log in can click the "Upload" button to jump to the upload view.

[[141394]]

Here, users can choose to enter notes and click "Select Picture" to use the system's standard image picker to get a photo from the photo library and upload it.

All of the above code has been implemented in the starter project. Now we need to implement the sendPressed(_:) code. This action method is connected to the "Send" button in the navigation bar. It sends the photo and note to the server.
The process consists of two parts: first, uploading the image using the PFFile object, and second, adding it to a PFObject and uploading it to the server.

We have seen before that we can use the setKey and objectForKey methods to add and get fields of PFObject. But now we need to use a specific object type (photo wall), at this time, a custom subclass can play a better role. Next you will see how to do it.

Customizing the Parse Object

Open the WallPost.swift file in the Model group. You will now see a simple class that inherits from the NSObject class. First, change the parent class so that it inherits from PFObject:

  1. class WallPost: PFObject {
  2. }

You also need the WallPost class to conform to the PFSubclassing protocol.

The PFSubclassing protocol defines some necessary methods for inheriting PFObject. The categories defined in PFObject+Subclass.h implement these methods, and what you need to do is to override them in your own subclass.

The specific method is to add an extension to the WallPost class, which contains these two necessary methods:

  1. extension WallPost: PFSubclassing {
  2. // Table view delegate methods here  
  3. //1  
  4. class func parseClassName() -> String {
  5. return   "WallPost"  
  6. }
  7.    
  8. //2  
  9. override class func initialize() {
  10. var onceToken: dispatch_once_t = 0  
  11. dispatch_once(&onceToken) {
  12. self.registerSubclass()
  13. }
  14. }
  15. }
  1. Set the class name according to the records in the backend database.
  2. Let Parse know that all objects of type WallPost will use this subclass. This method should only be called once, so we use the dispatch_once_t method.

Next, we add three properties to the WallPost class:

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

Here, we use the PFFile type image to store the uploaded photos, the PFUser type user to store user information, and the String type comment to store photo comments.

We use @NSManager because from a low-level perspective, the properties of PFObject are just a collection of key-value pairs. When we set a property, it is automatically set as a key-value pair.

In addition, we need to define a query() method in the subclass to return a PFQuery object. Add the following code to the WallPost.swift file:

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

Here is a detailed description of this code:

  1. Create a PFQuery object for the WallPost class.
  2. Call this method to return complete user information. Without this statement, the query will only return a reference to the current object without any member information.
  3. Sort by creation date.

***, we need to add an initialization method.

  1. init(image: PFFile, user: PFUser, comment: String?) {
  2. super .init()
  3.    
  4. self.image = image
  5. self.user = user
  6. self.comment = comment
  7. }
  8.    
  9. override init() {
  10. super .init()
  11. }

The above is a simple initialization method. Regardless of whether an initial value is given, a WallPost object can be created.

Now that WallPost is complete, let's move on to uploading photos.

Open UploadImageViewController.swift and add the following code to the end of sendPresed(_:) :

  1. //Upload a new picture  
  2. //1  
  3. let file = PFFile(name: "image" , data: pictureData)
  4. file.saveInBackgroundWithBlock({ (succeeded, error) -> Void in
  5. if succeeded {
  6. //2  
  7. self.saveWallPost(file)
  8. } else   if let error = error {
  9. //3  
  10. self.showErrorView(error)
  11. }
  12. }, progressBlock: { percent in
  13. //4  
  14. println( "Uploaded: \(percent)%" )
  15. })

Here are the detailed instructions:

  1. Create a PFFile object using the image data and then perform the save operation in the background.
  2. If successful, save the file's associated PostWall object.
  3. If unsuccessful, inform the user.
  4. Parse supports tracking the progress of saving files. You can use the progress block to know the current progress. Here we simply print the progress to the console.

Next, implement the saveWallPost(_:) method:

  1. func saveWallPost(file: PFFile)
  2. {
  3. //1  
  4. let wallPost = WallPost(image: file, user: PFUser.currentUser()!, comment: self.commentTextField.text)
  5. //2  
  6. wallPost.saveInBackgroundWithBlock{ succeeded, error in
  7. if succeeded {
  8. //3  
  9. self.navigationController?.popViewControllerAnimated( true )
  10. } else {
  11. //4  
  12. if let errorMessage = error?.userInfo?[ "error" ] as? String {
  13. self.showErrorView(error!)
  14. }
  15. }
  16. }
  17. }

The detailed instructions are as follows:

  1. Create a WallPost object based on the uploaded image, the currently logged-in user, and the image notes.
  2. The background saves the WallPost object.
  3. If successful, return to the photo wall.
  4. Otherwise, inform the user.

Build and run the app. Log in as the user you created earlier, enter the picture upload interface, click the "Select Picture" button, select a picture from the photo library, write a note, and click the "Send" button.

In the console you can see the percentage of the upload. Here we just display it in the console. In the final version of the app, it would be more appropriate to display a progress bar with this progress.

On the Dashboard, view the Core data and you will see a new table called WallPost. Not bad, but the only downside is that you can’t see the uploaded photos in the app.

Then our next step is to realize the function of retrieving photos.

#p#

Showcase photos on your photo wall

Open WallPicturesViewController.swift, this view will display all the photos uploaded by the user. When the view loads, it calls the getWallImages() method to get all the objects, which are currently empty.

For this to work, we first need to add some code to fetch the photos and place them on the wall. Add the loadWallViews(_:) method:

  1. func loadWallViews(objects: [WallPost]) {
  2. cleanWall()
  3.    
  4. var originY: CGFloat = 0  
  5.    
  6. for wallPost in objects {
  7. //1  
  8. let wallView = UIView(frame: CGRect(x: 0 , y: originY,
  9. width: self.wallScroll.frame.size.width, height: 270 ))
  10.    
  11. //2  
  12. wallPost.image.getDataInBackgroundWithBlock { data, error in
  13. if let data = data, image = UIImage(data: data) {
  14. //3  
  15. //Add the image  
  16. let imageView = UIImageView(image: image)
  17. imageView.frame = CGRect(x: 10 , y: 10 , width: wallView.frame.size.width - 20 , height: 200 )
  18. imageView.contentMode = UIViewContentMode.ScaleAspectFit
  19. wallView.addSubview(imageView)
  20.    
  21. //4  
  22. //Add the info label (User and creation date)  
  23. let creationDate = wallPost.createdAt
  24. let dateFormatter = NSDateFormatter()
  25. dateFormatter.dateFormat = "HH:mm dd/MM yyyy"  
  26.    
  27. let infoLabel = UILabel(frame: CGRect(x: 10 , y: 220 , width: 0 , height: 0 ))
  28. let dateString = dateFormatter.stringFromDate(creationDate!)
  29.    
  30. if let username = wallPost.user.username {
  31. infoLabel.text = "Uploaded by: \(username), \(dateString)"  
  32. } else {
  33. infoLabel.text = "Uploaded by anonymous: , \(dateString)"  
  34. }
  35.    
  36. infoLabel.text = "Uploaded by: \(wallPost.user.username), \(dateString)"  
  37. infoLabel.font = UIFont(name: "HelveticaNeue" , ​​size: 12 )
  38. infoLabel.textColor = UIColor.whiteColor()
  39. infoLabel.backgroundColor = UIColor.clearColor()
  40. infoLabel.sizeToFit()
  41. wallView.addSubview(infoLabel)
  42.    
  43. //5  
  44. //Add the comment label (User and creation date)  
  45. let commentLabel = UILabel(frame: CGRect(x: 10 , y: CGRectGetMaxY(infoLabel.frame)+ 5 , width: 0 , height: 0 ))
  46. commentLabel.text = wallPost.comment
  47. commentLabel.font = UIFont(name: "HelveticaNeue" , ​​size: 16 )
  48. commentLabel.textColor = UIColor.whiteColor()
  49. commentLabel.backgroundColor = UIColor.clearColor()
  50. commentLabel.sizeToFit()
  51. wallView.addSubview(commentLabel)
  52. }
  53. }
  54.    
  55. //6  
  56. wallScroll.addSubview(wallView)
  57. originY += 270  
  58. }
  59. //7  
  60. wallScroll.contentSize.height = CGFloat(originY)
  61. }

First we clear all UIView objects on the scrollview. Then we use the fast enumeration method to traverse the objects in the array, and for each object, perform the following steps:

  1. Create a view to display the image and details.
  2. Download image data.
  3. Add image view to photo wall.
  4. Get the information of the user who uploaded the image and put the creation date on the label.
  5. Add a label containing comment information.
  6. Place the above interface elements on the scroll view and add coordinates to indicate the next display position.
  7. Set the content size of the scrollview.

Now, replace the contents of the getWallImages() method:

  1. func getWallImages() {
  2. //1  
  3. let query = WallPost.query()!
  4. query.findObjectsInBackgroundWithBlock { objects, error in
  5. if error == nil {
  6. //2  
  7. if let objects = objects as? [WallPost] {
  8. self.loadWallViews(objects)
  9. }
  10. } else   if let error = error {
  11. //3  
  12. self.showErrorView(error)
  13. }
  14. }
  15. }

Detailed description:

  1. Create a simple query object to get WallPost objects and sort the results by creation date.
  2. Find an object that meets the criteria. Here, it is the WallPost object. If everything is OK, load the picture on the photo wall.
  3. If there is an error, prompt the user.

Build and run the app. You will see the pictures and notes you uploaded earlier. Take some time to play around with it and add more pictures and notes. Then check out the photo wall.

Pretty cool, isn't it?

Parse UI

As mentioned before, there is another way to display saved images. Let's take a look at this method next.

In the previous example, we used a simple UIScrollView object to display pictures, which requires us to calculate the content size ourselves. You may have thought that it might be better to use UITableView. Of course, smart Parse developers have already considered this, so they wrote ParseUI.framework, which provides a lot of convenient things to display Parse-related UI.

We mainly look at the following three:

  • PFQueryTableViewController: This is a subclass of UITableViewController. It can be used to easily display the results of a PFQuery in a table view.
  • PFTableViewCell: A subclass of UITableViewCell, used with PFQueryTableViewController.
  • PFImageView: A subclass of UIImageView that includes functionality for managing downloaded and displayed Parse images.

Now, open WallPicturesTableViewController.swift and change its superclass from UITableViewController to PFQueryTableViewController.

Of course, WallPostTableViewCell must also inherit from PFTableViewCell, and the type of the postImage object must also be changed to PFImageView.

Before writing any code, we need to make some changes to the storyboard. Open Main.storyboard and find the WallTableView scene:

Open the Attributes Inspector and you’ll see an option that includes a PFQueryTableViewController parameter:

These parameters allow you to choose the type of object to display in the table. You can also specify pull-to-refresh, paging, and loading interfaces. When using a simple UITableview to display the results, you can even set the key of the PFObject field to be displayed in the table without having to set it in code. In the Parse Class parameter, fill in WallPost.

Now go back to WallPicturesTableViewController.swift and add the following method:

  1. override func viewWillAppear(animated: Bool) {
  2. loadObjects()
  3. }
  4.    
  5. override func queryForTable() -> PFQuery {
  6. let query = WallPost.query()
  7. return query!
  8. }

Each time the photo wall interface is displayed, we want it to be reloaded. To specify the request to run, we override the queryForTable() method to return a query object for WallPost.

***, add the following tableview delegate method:

  1. override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject!) -> PFTableViewCell? {
  2. // 1  
  3. let cell = tableView.dequeueReusableCellWithIdentifier( "WallPostCell" , forIndexPath: indexPath) as! WallPostTableViewCell
  4.    
  5. // 2  
  6. let wallPost = object as! WallPost
  7.    
  8. // 3  
  9. cell.postImage.file = wallPost.image
  10. cell.postImage.loadInBackground(nil) { percent in
  11. cell.progressView.progress = Float(percent)* 0.01  
  12. println( "\(percent)%" )
  13. }
  14.    
  15. // 4  
  16. let creationDate = wallPost.createdAt
  17. let dateFormatter = NSDateFormatter()
  18. dateFormatter.dateFormat = "HH:mm dd/MM yyyy"  
  19. let dateString = dateFormatter.stringFromDate(creationDate!)
  20.    
  21. if let username = wallPost.user.username {
  22. cell.createdByLabel.text = "Uploaded by: \(username), \(dateString)"  
  23. } else {
  24. cell.createdByLabel.text = "Uploaded by anonymous: , \(dateString)"  
  25. }
  26.    
  27. cell.createdByLabel.text = "Uploaded by: \(wallPost.user.username), \(dateString)"  
  28.    
  29. cell.commentLabel.text = wallPost.comment
  30.    
  31. return cell
  32. }

This method replaces the native data source method of UITableView, tableView(_:cellForRowAtIndexPath:), which is more appropriate because it directly passes the PFObject object without looking up the corresponding object through the index path.

Let's take a look at the specific code explanation:

  1. Dequeue a cell object from the table view and convert it to WallPostTableViewCell type.
  2. Convert the PFObject object to the WallPost type.
  3. Call the loadInBackground method of PFImageView to download the image. Record the download progress in the completion closure. Here you need to display this progress on the UIProgressBar.
  4. Add creation date, user name, and comments to the cell.

There’s one last step before running the code. Open LoginViewController.swift and replace the scrollViewWallSegue with a tableViewWallSegue in loginPressed(_:) . Do the same in RegisterViewController.swift so that you can jump to the new version of the photo wall view.

Build and run the app. You’ll see the photo wall displayed in the table view, and a progress bar updating as the photos are downloaded.

#p#

Stay logged in, log out

You should have realized that every time the app is launched, the user needs to log in again. In addition, the "Log Out" button only takes the user to the main interface every time without actually logging out.

In the last part of the tutorial, we will add the ability to remember the logged-in state even if the app is restarted. We will also add a true logout feature.

Open LoginViewController.swift and add the following code to viewDidLoad():

  1. //Check if user exists and logged in  
  2. if let user = PFUser.currentUser() {
  3. if user.isAuthenticated() {
  4. self.performSegueWithIdentifier(scrollViewWallSegue, sender: nil)
  5. }
  6. }

Once the user is logged in, Parse will remember the user and state when the app is restarted. Here we use optional binding (if let) to check if the user currently exists. If so, we check if the user is authenticated. If so, the user is logged in and we jump directly to the photo wall view.

To log the user out, open WallPicturesTableViewController.swift, find logOutPressed(_:) and add the following code:

  1. @IBAction func logOutPressed(sender: AnyObject) {
  2. PFUser.logOut()
  3. navigationController?.popToRootViewControllerAnimated( true )
  4. }

Here we simply log out the current user and jump to the initial login interface. Remember to add the same logout code in WallPicturesViewController.swift.

Build, run, and you’re done!

What's next?

This link contains the complete example project: http://cdn4.raywenderlich.com/wp-content/uploads/2015/04/ParseTutorial-Finished.zip

You have seen how it is convenient to use PFObject subclasses to upload and download objects. You have also learned how to use PFUser in Parse.

You can accomplish more with Parse. Parse also supports sending push notifications to your users within the app. There are more social features integrated into the framework. You can also add data analysis to record user behavior.

Parse provides more advanced features, such as writing cloud code and scheduling recurring tasks in the background.

As you write your Parse apps, you’ll get to know it better, and I highly recommend you explore more advanced features.

Now, you should be confident about adding backend functions. Creating a cloud application is no longer an unattainable task.

I hope to see you build more apps based on Parse. If you have any questions or suggestions, please join the forum to discuss.

<<:  Microsoft releases ASP.NET 5 version roadmap

>>:  Share Button in Swift

Recommend

Share the Douyin Book List Project, a way to play without being on camera

The day before yesterday, I shared an article: &q...

How to create high-conversion information flow video content!

With regard to information flow advertising, ther...

OMG! Your devil Li Jiaqi is shooting a lipstick commercial!

Li Jiaqi, a man that women love and hate. It is s...

Interview with Zenny Chen: iOS developers should pay attention to Metal

[[120974]] CocoaChina: How did you get involved i...

How to promote an app without any budget?

This article is compiled from Zhihu: Zhihu user: ...

How to promote WeChat mini program to attract new users?

In the era of mobile Internet, traffic costs are ...

From Weibo to Toutiao to Zhihu, where are the three content giants going?

Weibo's market value today has reached 10 bil...

[Photo] iPhone 7/7 Plus performance review: crushing Android flagships

[[173106]] In this evaluation, AnandTech still us...

How to do data analysis on WeChat Official Account? Share 6 key points!

In fact, the meaning behind the data is logic and...

Otaku · Points management game rules make management easier

The rules of the Otaku Points-Based Management Ga...