Parse 教程:网络后台基础

jopen 9年前

Parse 教程:网络后台基础
本文由CocoaChina翻译组成员leon(社区ID)翻译自raywenderlich
原文:Parse Tutorial: Getting Started with Web Backends


2015.4.12日:本教程已针对Swift, iOS 8.3, Xcode 6.3及最新的Parse SDK(1.7.1版本)更新。


网络后台支持可以为你的App添加许多崭新的功能:不论是数据同步,社交分享,还是云端存储都可应付自如。作为一名专业的iOS开发者,如何才能为你的App添加服务器端的支持?

在本篇Parse教程中,你将会学到如何创建一个使用 Parse 后台支持的App,此App主要功能为照片分享,包含用户登录、照片上传和照片墙功能。为了使你集中精力在aParse的实现上,本工程预先包含了一部分用户界面,但不包括上传和现在照片的功能。你将一步一步地添加Parse服务,完成一个完整的App。

准备好轻松创建App了吗?好的,让我们开始了解Parse。

准备工作

开始App部分的开发工作前,第一步需要在后台创建Parse App。 每个开发者、每个App都需要一个唯一标识符,否则的话,你的数据和用户就会和别人的弄混。

访问 Parse.com,点击“Get started for free”, 然后点击注册创建一个新的账户。

创建账户后,Parse会询问你是否创建第一个App。 你必须为每个iOS App注册单独的后台App。在本教程中,我们叫它"Tutorial App"。Parse上可能存在许多app,它们的标识符各不相同,但是现在只有一个app实例属于你。

Parse 教程:网络后台基础

创建app后,你会看到欢迎界面,在上面有许多选项帮你添加Parse的功能。这些选项都会有模板功能供下载使用,但本教程暂时不需要。在网页顶端有几个选项按钮,如下图所示:

Parse 教程:网络后台基础

以下是这些选项的说明:

  • Core(核心):在这里你可以看到之前上传的所有数据,你也可以看到用户,并手动管理这些数据。

  • Analytics(分析):这里你可以考到关于App的数据统计,如数据流量,已发送的推送通知和API调用次数。你也可以添加自定义的事件。

  • Push(推送):使用这个功能可以向任一组用户发送推送通知。

  • Settings(设定):这里你可以看到所有API key。另外,你可以修改你的app的设定,管理安全选项,并且导出数据。

  • Docs(文档):在这里你可以看到教程、示例工程,API文档,学习到所有使用Parse扩展app功能的方法。

Parse示例程序

为了集中在后台服务上,该教程包含一个初始工程。你可以直接下载,然后按照教程步骤添加Parse调用。

使用Xcode打开工程并运行。首先,你将看到一个登陆页面。但这个页面上的按钮还不能做任何事情。稍后你会学到如何创建这些功能。

Parse 教程:网络后台基础

开始之前,先打开Main.storyboard文件,看看这个app的结构和流程。

Parse 教程:网络后台基础

该工程包含以下4个主视图:

  • 登录:登录界面有用户名和密码文本框,还有一个注册按钮用以创建新用户。

  • 注册:该界面用于输入用户名和密码在后台创建新的用户。

  • 图片墙:这是该应用的主视图。在此,可看到所有其他用户上传的图片、创建日期和照片评论。

  • 上传:在这个视图中,用户可以上传自己的图片到照片库,并添加一个备注(可选)。

每个视图在Storyboard中都有对应的UIViewController, 但你需要注意“照片墙”视图有两个表现形式。这是因为你要看到使用Parse实现该视图的两种方式。

Parse快速准备

第一步,自然是在使用Parse配置你的工程。

使用以下链接下载Parse iOS SDK:https://parse.com/downloads/ios/parse-library/latest

下载后,解压并拖拽frameworks文件夹下的三个framework文件到你的工程中。当提示框显示时,选择"Copy items..."和"Create groups..."。Xcode默认会将这些framework添加到"ParseTutorial"的target下,不需要额外配置。

  • Parse.framework: 这是最主要的framework, 包含了Parse所有的后台功能。

  • Bolts.framework: 这个framework是许多底层库的集合,它使许多任务变得轻松快捷。

  • ParseUI.framework: 这个framework包含一些非常方便的UI元素,可以直接和Parse对象进行交互。你将使用这个framework创建照片墙。

备注:当添加Parse到现有工程中时,你还需要添加一些Parse framework依赖的framework,如CoreGraphics和SystemConfiguration。我们的起始工程已经包含了这些,你可以在"Parse Quick Start Guide"中找到完整步骤。

Parse SDK是使用Objective-C实现的,而你将使用Swift去创建你的App,要在Swift程序中使用Parse Obj-C的SDK,你需要一个Objective-C桥接头文件(Objective-C bridging Header file)。

创建桥接头文件最简单的方法,就是在你的工程中添加任一Objective-C文件,这样,Xcode就会自动为你创建头文件。

Xcode中,选择File\New\File...并选择iOS\Source\Objective-C file模板。随意命名(我们稍后会删除该文件),然后保存。当你保存这个文件时,Xcode会提供一个Objective-C桥接头文件。如图所示:

Parse 教程:网络后台基础

点击Yes后,Xcode会创建桥接头文件并且添加到你的工程中。Objective-C文件已经用不上了,可以直接删除。

打开新创建的"ParseTutorial-Bridging-Header.h"文件,添加以下内容到文件底部:

#import #import #import

添加后,这三个framework就可以在Swift代码中使用。

接下来,你需要在Parse网站上API key供我们的app使用。在Parse Dashboard上打开你的app的Settings界面,在左边的面板上选择Keys按钮。记下application ID和Client Key。

Parse 教程:网络后台基础

下一步,打开AppDelegate.swift文件,定位到application(_:didFinishLaunchingWithOptions:)。在该方法起始处添加如下内容:

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

当然,需要在AppID和clientKey的位置要填入你之前记下的真实ID和Key。

Build后运行App。如果没有任何错误,意味着app已经注册并连接到Parse后台。你已经可以调用Parse相关的服务了。

下个步骤中,我们要创建一些示例对象。

创建示例对象

每个上传的Parse对象都会成为访问数据库结构的入口。你可以把这些对象看做是字典——事先存储以关键字标示的数据,然后你就可以通过关键字取到对象。

在该例子中,你将上传一个叫做“Player”的对象,包含“Name”和“Score”两个字段。因此在数据库中,将会有一个叫“Player”的表包含所有以“Player”名字上传的对象。稍后你会看到这个例子。

打开AppDelegate.swift,添加以下代码到application(_:didFinishLaunchingWithOptions:)方法中,注意放到return true之前。

let player = PFObject(className: "Player")  player.setObject("John", forKey: "Name")  player.setObject(1230, forKey: "Score")  player.saveInBackgroundWithBlock { (succeeded, error) -> Void in    if succeeded {      println("Object Uploaded")    } else {      println("Error: \(error) \(error.userInfo!)")    }  }

正如你看到的,上传对象的代码是异步的,你将在闭包中检查到返回结果。

PFObject是Parse中的一个基类,它提供了一些基本的对象操作方法。最大的好处是,你不需要在Parse网站上创建表,Parse会基于你提交的对象创建表结构。

构建,运行。如果你正确放置了API key,且app正确注册了Parse服务,app应该正常运行。否则,你将收到错误信息。

等等,你的对象去哪了?只是漂浮在网络空间吗?

想要正确查看你保存的对象,只需要打开Parse的dashboard,点击Core,你就能看到如下图所示的对象:

Parse 教程:网络后台基础

恭喜你,你已经成功的和网络后台进行交互。

注意:如果你在iOS模拟器上运行app,并看到错误信息如“The network connection was lost”。请尝试重启模拟器。其他的网络错误也可以用这个方法试一下。

若你已经获得“Object Uploaded”消息,但在Dashboard上没有看到数据,请点击右上方的“Refresh”按钮刷新Dashboard页面。

进行下一步之前,先创建另外一条数据。设置name为“John”,score为810.现在你有两条数据,name都为John,但score不同。再添加第三条数据,name为“Sally”, score为2400。

获取对象

现在,我们尝试一下获取对象。Parse中有PFQuery类来支持这个功能。它可以执行数据请求,你可以在 PFQuery documentation 中查看到更多资料。

让我们来实现获取符合如下条件的对象:

score大于1000,且name等于“John”,注释掉(或删除)之前的代码,不然的话每次运行都会上传一个新的对象。然后放置如下代码:

// 1  let query = PFQuery(className: "Player")  // 2  query.whereKey("Name", equalTo: "John")  query.whereKey("Score", greaterThan: 1000)  // 3  query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in    if error == nil {      println("Successfully retrieved: \(objects)")    } else {      println("Error: \(error) \(error.userInfo!)")    }  }

1. 这里我们创建了数据请求的对象,class name即为表名。

2. 通过whereKey方法,指定只获取符合条件的对象(name为John,score大于1000)

3. 发送请求,然后在闭包中打印结果。

再次构建并运行app,数据请求是异步的,因此不会对拖慢UI显示的速度——这会使用户更满意。在控制台中,你应该会看到所有符合条件的对象,如图所示:

Parse 教程:网络后台基础

现在我们已经探索了存储和获取数据的基本操作,我们在真实项目里应用一下。

记得先注释掉application(_:didFinishLaunchingWithOptions:) 中我们刚写的代码。

用户注册

首先,用户会使用我们的app注册账号。

打开RegisterViewController.swift, 当前这个界面什么都干不了。我们的任务就是实现点击“Sign Up”按钮后的功能。

定位到signUpPressed(_:)方法中,将代码替换为:

@IBAction func signUpPressed(sender: AnyObject) {    //1    let user = PFUser()       //2    user.username = userTextField.text    user.password = passwordTextField.text       //3    user.signUpInBackgroundWithBlock { succeeded, error in      if (succeeded) {        //The registration was successful, go to the wall        self.performSegueWithIdentifier(self.scrollViewWallSegue, sender: nil)      } else if let error = error {        //Something bad has occurred        self.showErrorView(error)      }    }  }

以上代码中,按照如下步骤创建用户:

1. 创建PFUser对象,赋值给user。你将使用这个对象来完成登录和注册流程。它将存储你的认证用户信息,这样你就可以访问该用户的数据了。你可以通过该链接访问PFUser的文档:http://www.parse.com/docs/ios/api/Classes/PFUser.html

2. 取得界面上username和password文本框的内容,分别给user对象中相应的字段赋值。

3. 后台调用注册的方法,然后检查返回值。可能有两种结果:返回正常证明已成功创建了用户,并以该用户的身份登录;若有错误为创建失败。创建成功后就直接跳转到照片墙界面,否则则给出错误提示。

构建、运行app查看是否有错误。在Log In界面中,点击Sign Up按钮,你将看到如下界面:

Parse 教程:网络后台基础

输入用户名、密码,点击Sign Up 按钮,若一切正常的话你将跳转到照片墙界面。

不错,不过保险起见,我们还是验证一下新用户是否真的已经在表中创建成功:Dashboard中打开User选项,如下所示:

Parse 教程:网络后台基础

恭喜!你已经创建了第一个用户。现在让我们用这个用户登录,在做些有意思的事情。

登录

打开LoginViewController.swift类,找到一下方法:

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

正如你所见到的,这个方法和注册流程中的十分相似。这里我们还要用到PFUser,不过是要用做登录的。替换方法中的代码:

@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)      }    }  }

流程非常简单。跳转到下个界面前,我们首先要检查用户名和密码是否能和数据库中的记录匹配。

构建、运行程序,效果如下:

Parse 教程:网络后台基础

尝试用我们创建的用户登录,如果一切正常,app将会跳转到照片墙界面。保险起见,可以尝试用错误的用户名或密码来登录,看是否有错误代码显示。

发送照片到照片墙

之前的注册、登录操作都会跳转到照片墙视图。在这个视图中,你会看到所有用户上传的图片和评论。

在那之前,我们得先上传一些图片。

使用Parse上传文件很简单。打开UploadImageViewController.swift,我们将在这个类中实现上传功能。

所有用户登录后都可以点击“Upload”按钮跳转到上传视图。

Parse 教程:网络后台基础

在这里,用户可以选择输入备注并点击“Select Picture”,使用系统标准的image picker从照片库中获取照片,上传。

所有上述代码已经在起始工程中实现,现在我们需要实现sendPressed(_:)代码。这个action方法连接到导航栏的“Send”按钮上。它将照片和备注发送到服务器上。
该过程包含两个部分,一是使用PFFile对象上传图片,二是将其添加到PFObject,并上传至服务器。

之前我们已经看到,可以使用setKey和objectForKey方法添加和获取PFObject的字段。但现在我们需要用到特定的对象类型(照片墙),这时,自定义的子类可以更好的发挥作用。接下来你会看到如何实现。

自定义Parse对象

打开Model group下的WallPost.swift文件。当前你会看到继承自NSObject类的简单类。首先,修改父类,使其继承自PFObject:

class WallPost: PFObject {    }

你还需要WallPost类遵循PFSubclassing协议。

PFSubclassing协议 定义了一些继承PFObject的必要方法。PFObject+Subclass.h中定义的category实现了这些方法,你需要做的是在自己的子类中重写它们。

具体做法是在WallPost类中添加扩展,扩展中包含这两个必要方法:

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. 按照后台数据库的记录设置类名。

2. 让Parse知道:所有类的类型为WallPost的对象,都将使用该子类。这个方法只应被调用一次,因此我们使用dispatch_once_t方法。

接下来,我们为WallPost类添加三个属性:

  • @NSManaged var image: PFFile

  • @NSManaged var user: PFUser

  • @NSManaged var comment: String?

这里,我们用PFFile类型的image放置上传用的照片,PFUser类型的user保存用户信息,还有String类型的comment保存照片备注。

我们使用了@NSManager,因为从底层角度来看,PFObject的属性只是一些键值对参数的集合。当我们设置某一个属性的时候,会自动被作为键值对设置。

另外,在子类中我们需要定义一个query()方法,返回PFQuery对象,添加以下代码到WallPost.swift文件:

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

以下是这段代码的详细说明:

1. 为WallPost类创建PFQuery对象。

2. 调用该方法以返回完整的user信息。若没有这句,该query只会返回当前对象的引用,而不包含任何成员的信息。

3. 按照创建日期排序。

最后,我们需要添加初始化方法。

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

以上就是一个简单的初始化方法,不管是否给定初始值,都可以创建一个WallPost对象。

WallPost已经完成,让我们继续上传照片的工作。

打开UploadImageViewController.swift, 在sendPresed(_:)方法末尾处,添加以下代码:

//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)%")  })

以下是详细说明:

1. 使用image data创建PFFile对象,然后在后台执行保存动作。

2. 如果成功,保存文件相关PostWall对象。

3. 如果不成功,告知用户。

4. 保存文件时,Parse支持跟踪保存进度。通过progress block即可得知当前进度。这里我们只是简单的把进度打印到控制台。

接下来实现saveWallPost(_:)方法:

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!)        }      }    }  }

详细说明如下:

1. 根据上传图片、当前已登录用户和图片备注创建WallPost对象。

2. 后台保存WallPost对象。

3. 如果成功,返回照片墙。

4. 否则,告知用户。

构建、运行app。登录之前创建的用户,进入图片上传界面,点击“Select Picture”按钮,从照片库中选择一张图片,然后随便写一条备注,点击“Send”按钮。

在控制台上你可以看到上传的百分比。这里只是将其显示在控制台上,在最终版的app中,使用该进度显示一个progress bar更合适。

在Dashboard上,查看Core数据,你将会看到一个新的表,名为WallPost。不错,但是唯一的不足是你没有办法在app上看到上传的照片。

那么我们下一步就来实现取回照片的功能。

在照片墙上展示照片
打开WallPicturesViewController.swift,该视图将会显示所有用户上传的照片。当该视图加载时,它会调用getWallImages()方法来获取所有对象,当前其为空。

要是其可以工作,我们得先添加一些代码,在获取照片后放置它们在照片墙。添加loadWallViews(_:)方法:

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)  }

首先我们清除scrollview上所有的UIView对象.然后我们使用快速枚举的方法遍历数组中的对象,针对每一个对象,执行以下步骤:

1. 创建一个视图来显示图片和详情。

2. 下载图片数据。

3. 添加图片视图到照片墙。

4. 获取上传图片的用户的信息,将创建日期放置在label上。

5. 添加包含备注信息的label。

6. 将上述界面元素放置到scroll view上,并且增加用以指示下个显示位置的坐标。

7. 设置scrollview的content size。

现在,替换getWallImages()方法的内容:

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)      }    }  }

详细说明:

1. 创建一个简单的query 对象来获取WallPost对象,并将结果按照创建日期排序。

2. 查找到符合条件的对象。这里,即为WallPost对象。如果一切正常,则在照片墙上加载图片。

3. 如果有错误的话,提示用户。

构建、运行app。你将看到之前上传的图片和备注信息。花点时间玩一下,再多添加些图片和备注。然后在照片墙上看看。

很酷,不是吗?

Parse UI

之前提过,还有另外一种展示保存图片的方法。接下来我们看一下这种方法。

前面的例子中,我们使用了一个简单的UIScrollView对象来展示图片,这需要我们自己来计算content size。你可能想过使用UITableView可能更好,当然,聪明的Parse开发者早就考虑到了,因此,它们编写了ParseUI.framework,提供了很多方便的东西来显示Parse相关的UI。

我们主要看看以下三个:

  • PFQueryTableViewController:这是UITableViewController的子类。可以用来很方便的在table view中显示PFQuery的结果。

  • PFTableViewCell:UITableViewCell的子类,和PFQueryTableViewController搭配使用。

  • PFImageView:UIImageView的子类,包含管理下载和显示Parse图片的功能。

现在,打开WallPicturesTableViewController.swift将它的父类从UITableViewController 修改为PFQueryTableViewController。

当然,WallPostTableViewCell也要继承自PFTableViewCell,其中的postImage对象的类型也要改为PFImageView。

编写代码之前,我们需要对storybaord做些修改。打开Main.storyboard,找到WallTableView scene:

Parse 教程:网络后台基础

打开属性查看器(Attributes Inspector),你会看到一个包含PFQueryTableViewController参数的选项:

Parse 教程:网络后台基础

这些参数可以让你选择显示在table上的对象类型。并且可以指定下拉刷新、分页和loading界面。当使用简单的UITableview来展示结果时,你甚至可以设置table中要显示的PFObject字段的key,而不需要动手在代码中去设置。在Parse Class的参数中,填入WallPost。

现在回到WallPicturesTableViewController.swift文件,添加以下方法:

override func viewWillAppear(animated: Bool) {    loadObjects()  }     override func queryForTable() -> PFQuery {    let query = WallPost.query()    return query!  }

每次显示照片墙界面,我们都希望它被重新加载。为了指定运行的请求,我们重写queryForTable()方法为WallPost返回一个query对象。

最后,添加以下tableview的delegate方法:

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  }

这个方法替换掉UITableView原生的data source方法tableView(_:cellForRowAtIndexPath:),这样的形式更合适,因为它直接传递PFObject对象,而不需要通过index path查找对应的对象。

我们来看一下具体的代码解释:

1. 从table view中dequeue出一个cell对象,转换成WallPostTableViewCell类型。

2. 转换PFObject对象为WallPost类型。

3. 调用PFImageView的loadInBackground方法,下载图片。在complete closure中记录下载进度。这里你需要将这个进度显示在UIProgressBar上。

4. 添加创建日期、用户名和备注到cell上。

运行代码前,还有最后一个步骤.打开LoginViewController.swift,在loginPressed(_:)方法中,将scrollViewWallSegue替换为tableViewWallSegue。在RegisterViewController.swift中,也进行同样的替换,这样就可以正常跳转到新版本的照片墙视图。

构建、运行app, 你会看到照片墙显示在table view上,图片下载时,还能看到进度条更新进度。

保持登入、登出

你应该已经意识到,每次app启动时,用户都需要重新登录。另外,"Log Out"按钮每次只是将用户带到主界面,而没有实际的登出功能。

在教程的最后,我们将添加记住登录状态的功能,即使app重新启动,登录状态也会保持。另外,我们还会添加真正的登出功能。

打开LoginViewController.swift,添加以下代码到viewDidLoad()方法中:

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

当用户登录后,Parse将会在app重启时记录用户和状态。这里我们用可选值绑定(if let)检查当前是否存在用户。如果存在,我们检查用户是否已认证,若已认证,证明用户已登录,直接跳转到照片墙视图。

要登出用户,打开WallPicturesTableViewController.swift, 找到logOutPressed(_:)方法,添加以下代码:

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

这里我们简单地登出当前用户,并跳转到初始的登录界面。记得在WallPicturesViewController.swift中添加同样的登出代码。

构建、运行,大功告成!

下一步做什么?

这个链接包含了完整的实例工程:http://cdn4.raywenderlich.com/wp-content/uploads/2015/04/ParseTutorial-Finished.zip

你已经看到了使用PFObject子类上传、下载对象是如何便利。也学到了在Parse使用PFUser的方法。

使用Parse可以完成更多的工作。Parse还支持在app内部给你的用户发送推送通知。还有更多的社交功能已经集成到framework中。你也可以添加数据分析记录用户行为。

Parse提供更多高级特性,例如编写云端代码,在后台安排可循环执行的计划任务。

在你编写Parse app的过程中,你会更加了解它。本人强烈推荐你探索更多高级的特性。

现在,对于添加后台功能这件事,你应该已经信心十足了。如何创建一个云端应用,现在已经不是一件高不可攀的事情了。

希望看到你做出更多基于Parse的app。如果有任何问题或建议,请加入论坛,一起讨论。