Parse 教程:网络后台基础

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

[[141390]]

本教程已针对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实例属于你。

39.png

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

40.png

以下是这些选项的说明:

  • Core(核心):在这里你可以看到之前上传的所有数据,你也可以看到用户,并手动管理这些数据。
  • Analytics(分析):这里你可以考到关于App的数据统计,如数据流量,已发送的推送通知和API调用次数。你也可以添加自定义的事件。
  • Push(推送):使用这个功能可以向任一组用户发送推送通知。
  • Settings(设定):这里你可以看到所有API key。另外,你可以修改你的app的设定,管理安全选项,并且导出数据。
  • Docs(文档):在这里你可以看到教程、示例工程,API文档,学习到所有使用Parse扩展app功能的方法。

Parse示例程序

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

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

42.png

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

43.png

该工程包含以下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桥接头文件。如图所示:

44.png

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

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

  1. #import #import #import 

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

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

45.png

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

  1. 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之前。

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

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

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

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

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

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

47.png

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

注意:如果你在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. // 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.   } 
  1. 这里我们创建了数据请求的对象,class name即为表名。
  2. 通过whereKey方法,指定只获取符合条件的对象(name为John,score大于1000)
  3. 发送请求,然后在闭包中打印结果。

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

48.png

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

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

用户注册

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

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

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

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

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

  1. 创建PFUser对象,赋值给user。你将使用这个对象来完成登录和注册流程。它将存储你的认证用户信息,这样你就可以访问该用户的数据了。你可以通过该链接访问PFUser的文档:http://www.parse.com/docs/ios/api/Classes/PFUser.html
  2. 取得界面上username和password文本框的内容,分别给user对象中相应的字段赋值。
  3. 后台调用注册的方法,然后检查返回值。可能有两种结果:返回正常证明已成功创建了用户,并以该用户的身份登录;若有错误为创建失败。创建成功后就直接跳转到照片墙界面,否则则给出错误提示。

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

[[141393]]

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

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

50.png

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

登录

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

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

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

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

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

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

51.png

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

#p#

发送照片到照片墙

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

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

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

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

[[141394]]

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

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

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

自定义Parse对象

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

  1. class WallPost: PFObject {   

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

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

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

 
  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.   } 
  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文件:

 
  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 

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

  1. 为WallPost类创建PFQuery对象。
  2. 调用该方法以返回完整的user信息。若没有这句,该query只会返回当前对象的引用,而不包含任何成员的信息。
  3. 按照创建日期排序。

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

  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. override init() { 
  9.   super.init() 

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

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

打开UploadImageViewController.swift, 在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. }) 

以下是详细说明:

  1. 使用image data创建PFFile对象,然后在后台执行保存动作。
  2. 如果成功,保存文件相关PostWall对象。
  3. 如果不成功,告知用户。
  4. 保存文件时,Parse支持跟踪保存进度。通过progress block即可得知当前进度。这里我们只是简单的把进度打印到控制台。

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

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

详细说明如下:

  1. 根据上传图片、当前已登录用户和图片备注创建WallPost对象。
  2. 后台保存WallPost对象。
  3. 如果成功,返回照片墙。
  4. 否则,告知用户。

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

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

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

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

#p#

在照片墙上展示照片

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

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

 
  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) 

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

  1. 创建一个视图来显示图片和详情。
  2. 下载图片数据。
  3. 添加图片视图到照片墙。
  4. 获取上传图片的用户的信息,将创建日期放置在label上。
  5. 添加包含备注信息的label。
  6. 将上述界面元素放置到scroll view上,并且增加用以指示下个显示位置的坐标。
  7. 设置scrollview的content size。

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

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

详细说明:

  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:

55.png

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

56.png

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

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

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

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

***,添加以下tableview的delegate方法:

 
  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 

这个方法替换掉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上,图片下载时,还能看到进度条更新进度。

#p#

保持登入、登出

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

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

打开LoginViewController.swift,添加以下代码到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.   } 

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

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

  1. @IBAction func logOutPressed(sender: AnyObject) { 
  2.   PFUser.logOut() 
  3.   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。如果有任何问题或建议,请加入论坛,一起讨论。

责任编辑:倪明 来源: raywenderlich'文章
相关推荐

2011-07-15 14:19:10

故障恢复控制台

2011-07-11 10:30:46

2022-07-06 07:48:38

分布式存储架构

2015-06-24 10:06:09

iOS 9适配后台

2010-06-11 13:53:54

UML建模

2018-11-28 14:30:49

权限系统数据

2014-05-04 13:47:39

锐捷网络极简网络

2011-08-10 15:48:10

iPhone网络

2021-11-22 08:50:20

Kubernetes网络策略云原生应用程序

2011-06-02 10:28:11

网络命令

2017-12-12 07:47:59

dockermarathon服务器

2011-07-21 10:17:53

java

2017-07-18 10:14:23

OracleMerge into教程

2011-07-18 09:35:29

iPhone 框架

2009-07-22 13:32:43

iBATIS DAO

2020-10-17 09:48:55

Spinnaker实践

2021-07-14 10:29:30

REvil勒索软件基础设施

2011-03-10 15:34:21

网络管理

2022-05-02 18:45:33

Kubernetes网络模型

2011-08-09 16:58:22

XCodeSDK
点赞
收藏

51CTO技术栈公众号