本教程已针对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实例属于你。
创建app后,你会看到欢迎界面,在上面有许多选项帮你添加Parse的功能。这些选项都会有模板功能供下载使用,但本教程暂时不需要。在网页顶端有几个选项按钮,如下图所示:
以下是这些选项的说明:
- Core(核心):在这里你可以看到之前上传的所有数据,你也可以看到用户,并手动管理这些数据。
- Analytics(分析):这里你可以考到关于App的数据统计,如数据流量,已发送的推送通知和API调用次数。你也可以添加自定义的事件。
- Push(推送):使用这个功能可以向任一组用户发送推送通知。
- Settings(设定):这里你可以看到所有API key。另外,你可以修改你的app的设定,管理安全选项,并且导出数据。
- Docs(文档):在这里你可以看到教程、示例工程,API文档,学习到所有使用Parse扩展app功能的方法。
Parse示例程序
为了集中在后台服务上,该教程包含一个初始工程。你可以直接下载,然后按照教程步骤添加Parse调用。
使用Xcode打开工程并运行。首先,你将看到一个登陆页面。但这个页面上的按钮还不能做任何事情。稍后你会学到如何创建这些功能。
开始之前,先打开Main.storyboard文件,看看这个app的结构和流程。
该工程包含以下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桥接头文件。如图所示:
点击Yes后,Xcode会创建桥接头文件并且添加到你的工程中。Objective-C文件已经用不上了,可以直接删除。
打开新创建的"ParseTutorial-Bridging-Header.h"文件,添加以下内容到文件底部:
- #import #import #import
接下来,你需要在Parse网站上API key供我们的app使用。在Parse Dashboard上打开你的app的Settings界面,在左边的面板上选择Keys按钮。记下application ID和Client Key。
下一步,打开AppDelegate.swift文件,定位到application(_:didFinishLaunchingWithOptions:)。在该方法起始处添加如下内容:
- Parse.setApplicationId("--AppID Goes Here--", clientKey: "--ClientKey Goes Here--")
当然,需要在AppID和clientKey的位置要填入你之前记下的真实ID和Key。
Build后运行App。如果没有任何错误,意味着app已经注册并连接到Parse后台。你已经可以调用Parse相关的服务了。
下个步骤中,我们要创建一些示例对象。
#p#
创建示例对象
每个上传的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,你就能看到如下图所示的对象:
恭喜你,你已经成功的和网络后台进行交互。
注意:如果你在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!)")
- }
- }
- 这里我们创建了数据请求的对象,class name即为表名。
- 通过whereKey方法,指定只获取符合条件的对象(name为John,score大于1000)
- 发送请求,然后在闭包中打印结果。
再次构建并运行app,数据请求是异步的,因此不会对拖慢UI显示的速度——这会使用户更满意。在控制台中,你应该会看到所有符合条件的对象,如图所示:
现在我们已经探索了存储和获取数据的基本操作,我们在真实项目里应用一下。
记得先注释掉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)
- }
- }
- }
以上代码中,按照如下步骤创建用户:
- 创建PFUser对象,赋值给user。你将使用这个对象来完成登录和注册流程。它将存储你的认证用户信息,这样你就可以访问该用户的数据了。你可以通过该链接访问PFUser的文档:http://www.parse.com/docs/ios/api/Classes/PFUser.html
- 取得界面上username和password文本框的内容,分别给user对象中相应的字段赋值。
- 后台调用注册的方法,然后检查返回值。可能有两种结果:返回正常证明已成功创建了用户,并以该用户的身份登录;若有错误为创建失败。创建成功后就直接跳转到照片墙界面,否则则给出错误提示。
构建、运行app查看是否有错误。在Log In界面中,点击Sign Up按钮,你将看到如下界面:
输入用户名、密码,点击Sign Up 按钮,若一切正常的话你将跳转到照片墙界面。
不错,不过保险起见,我们还是验证一下新用户是否真的已经在表中创建成功:Dashboard中打开User选项,如下所示:
恭喜!你已经创建了***个用户。现在让我们用这个用户登录,在做些有意思的事情。
登录
打开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)
- }
- }
- }
流程非常简单。跳转到下个界面前,我们首先要检查用户名和密码是否能和数据库中的记录匹配。
构建、运行程序,效果如下:
尝试用我们创建的用户登录,如果一切正常,app将会跳转到照片墙界面。保险起见,可以尝试用错误的用户名或密码来登录,看是否有错误代码显示。
#p#
发送照片到照片墙
之前的注册、登录操作都会跳转到照片墙视图。在这个视图中,你会看到所有用户上传的图片和评论。
在那之前,我们得先上传一些图片。
使用Parse上传文件很简单。打开UploadImageViewController.swift,我们将在这个类中实现上传功能。
所有用户登录后都可以点击“Upload”按钮跳转到上传视图。
在这里,用户可以选择输入备注并点击“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()
- }
- }
- }
- 按照后台数据库的记录设置类名。
- 让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
- }
以下是这段代码的详细说明:
- 为WallPost类创建PFQuery对象。
- 调用该方法以返回完整的user信息。若没有这句,该query只会返回当前对象的引用,而不包含任何成员的信息。
- 按照创建日期排序。
***,我们需要添加初始化方法。
- 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)%")
- })
以下是详细说明:
- 使用image data创建PFFile对象,然后在后台执行保存动作。
- 如果成功,保存文件相关PostWall对象。
- 如果不成功,告知用户。
- 保存文件时,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!)
- }
- }
- }
- }
详细说明如下:
- 根据上传图片、当前已登录用户和图片备注创建WallPost对象。
- 后台保存WallPost对象。
- 如果成功,返回照片墙。
- 否则,告知用户。
构建、运行app。登录之前创建的用户,进入图片上传界面,点击“Select Picture”按钮,从照片库中选择一张图片,然后随便写一条备注,点击“Send”按钮。
在控制台上你可以看到上传的百分比。这里只是将其显示在控制台上,在最终版的app中,使用该进度显示一个progress bar更合适。
在Dashboard上,查看Core数据,你将会看到一个新的表,名为WallPost。不错,但是唯一的不足是你没有办法在app上看到上传的照片。
那么我们下一步就来实现取回照片的功能。
#p#
在照片墙上展示照片
打开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对象.然后我们使用快速枚举的方法遍历数组中的对象,针对每一个对象,执行以下步骤:
- 创建一个视图来显示图片和详情。
- 下载图片数据。
- 添加图片视图到照片墙。
- 获取上传图片的用户的信息,将创建日期放置在label上。
- 添加包含备注信息的label。
- 将上述界面元素放置到scroll view上,并且增加用以指示下个显示位置的坐标。
- 设置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)
- }
- }
- }
详细说明:
- 创建一个简单的query 对象来获取WallPost对象,并将结果按照创建日期排序。
- 查找到符合条件的对象。这里,即为WallPost对象。如果一切正常,则在照片墙上加载图片。
- 如果有错误的话,提示用户。
构建、运行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:
打开属性查看器(Attributes Inspector),你会看到一个包含PFQueryTableViewController参数的选项:
这些参数可以让你选择显示在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查找对应的对象。
我们来看一下具体的代码解释:
- 从table view中dequeue出一个cell对象,转换成WallPostTableViewCell类型。
- 转换PFObject对象为WallPost类型。
- 调用PFImageView的loadInBackground方法,下载图片。在complete closure中记录下载进度。这里你需要将这个进度显示在UIProgressBar上。
- 添加创建日期、用户名和备注到cell上。
运行代码前,还有***一个步骤.打开LoginViewController.swift,在loginPressed(_:)方法中,将scrollViewWallSegue替换为tableViewWallSegue。在RegisterViewController.swift中,也进行同样的替换,这样就可以正常跳转到新版本的照片墙视图。
构建、运行app, 你会看到照片墙显示在table view上,图片下载时,还能看到进度条更新进度。
#p#
保持登入、登出
你应该已经意识到,每次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。如果有任何问题或建议,请加入论坛,一起讨论。