Parse 教程:網(wǎng)絡(luò)后臺基礎(chǔ)
本教程已針對Swift, iOS 8.3, Xcode 6.3及***的Parse SDK(1.7.1版本)更新。
網(wǎng)絡(luò)后臺支持可以為你的App添加許多嶄新的功能:不論是數(shù)據(jù)同步,社交分享,還是云端存儲都可應(yīng)付自如。作為一名專業(yè)的iOS開發(fā)者,如何才能為你的App添加服務(wù)器端的支持?
在本篇Parse教程中,你將會學(xué)到如何創(chuàng)建一個使用 Parse 后臺支持的App,此App主要功能為照片分享,包含用戶登錄、照片上傳和照片墻功能。為了使你集中精力在aParse的實現(xiàn)上,本工程預(yù)先包含了一部分用戶界面,但不包括上傳和現(xiàn)在照片的功能。你將一步一步地添加Parse服務(wù),完成一個完整的App。
準(zhǔn)備好輕松創(chuàng)建App了嗎?好的,讓我們開始了解Parse。
準(zhǔn)備工作
開始App部分的開發(fā)工作前,***步需要在后臺創(chuàng)建Parse App。 每個開發(fā)者、每個App都需要一個唯一標(biāo)識符,否則的話,你的數(shù)據(jù)和用戶就會和別人的弄混。
訪問 Parse.com,點擊“Get started for free”, 然后點擊注冊創(chuàng)建一個新的賬戶。
創(chuàng)建賬戶后,Parse會詢問你是否創(chuàng)建***個App。 你必須為每個iOS App注冊單獨的后臺App。在本教程中,我們叫它"Tutorial App"。Parse上可能存在許多app,它們的標(biāo)識符各不相同,但是現(xiàn)在只有一個app實例屬于你。
創(chuàng)建app后,你會看到歡迎界面,在上面有許多選項幫你添加Parse的功能。這些選項都會有模板功能供下載使用,但本教程暫時不需要。在網(wǎng)頁頂端有幾個選項按鈕,如下圖所示:
以下是這些選項的說明:
- Core(核心):在這里你可以看到之前上傳的所有數(shù)據(jù),你也可以看到用戶,并手動管理這些數(shù)據(jù)。
- Analytics(分析):這里你可以考到關(guān)于App的數(shù)據(jù)統(tǒng)計,如數(shù)據(jù)流量,已發(fā)送的推送通知和API調(diào)用次數(shù)。你也可以添加自定義的事件。
- Push(推送):使用這個功能可以向任一組用戶發(fā)送推送通知。
- Settings(設(shè)定):這里你可以看到所有API key。另外,你可以修改你的app的設(shè)定,管理安全選項,并且導(dǎo)出數(shù)據(jù)。
- Docs(文檔):在這里你可以看到教程、示例工程,API文檔,學(xué)習(xí)到所有使用Parse擴(kuò)展app功能的方法。
Parse示例程序
為了集中在后臺服務(wù)上,該教程包含一個初始工程。你可以直接下載,然后按照教程步驟添加Parse調(diào)用。
使用Xcode打開工程并運(yùn)行。首先,你將看到一個登陸頁面。但這個頁面上的按鈕還不能做任何事情。稍后你會學(xué)到如何創(chuàng)建這些功能。
開始之前,先打開Main.storyboard文件,看看這個app的結(jié)構(gòu)和流程。
該工程包含以下4個主視圖:
- 登錄:登錄界面有用戶名和密碼文本框,還有一個注冊按鈕用以創(chuàng)建新用戶。
- 注冊:該界面用于輸入用戶名和密碼在后臺創(chuàng)建新的用戶。
- 圖片墻:這是該應(yīng)用的主視圖。在此,可看到所有其他用戶上傳的圖片、創(chuàng)建日期和照片評論。
- 上傳:在這個視圖中,用戶可以上傳自己的圖片到照片庫,并添加一個備注(可選)。
每個視圖在Storyboard中都有對應(yīng)的UIViewController, 但你需要注意“照片墻”視圖有兩個表現(xiàn)形式。這是因為你要看到使用Parse實現(xiàn)該視圖的兩種方式。
Parse快速準(zhǔn)備
***步,自然是在使用Parse配置你的工程。
使用以下鏈接下載Parse iOS SDK:https://parse.com/downloads/ios/parse-library/latest
下載后,解壓并拖拽frameworks文件夾下的三個framework文件到你的工程中。當(dāng)提示框顯示時,選擇"Copy items..."和"Create groups..."。Xcode默認(rèn)會將這些framework添加到"ParseTutorial"的target下,不需要額外配置。
- Parse.framework: 這是最主要的framework, 包含了Parse所有的后臺功能。
- Bolts.framework: 這個framework是許多底層庫的集合,它使許多任務(wù)變得輕松快捷。
- ParseUI.framework: 這個framework包含一些非常方便的UI元素,可以直接和Parse對象進(jìn)行交互。你將使用這個framework創(chuàng)建照片墻。
備注:當(dāng)添加Parse到現(xiàn)有工程中時,你還需要添加一些Parse framework依賴的framework,如CoreGraphics和SystemConfiguration。我們的起始工程已經(jīng)包含了這些,你可以在"Parse Quick Start Guide"中找到完整步驟。
Parse SDK是使用Objective-C實現(xiàn)的,而你將使用Swift去創(chuàng)建你的App,要在Swift程序中使用Parse Obj-C的SDK,你需要一個Objective-C橋接頭文件(Objective-C bridging Header file)。
創(chuàng)建橋接頭文件最簡單的方法,就是在你的工程中添加任一Objective-C文件,這樣,Xcode就會自動為你創(chuàng)建頭文件。
Xcode中,選擇File\New\File...并選擇iOS\Source\Objective-C file模板。隨意命名(我們稍后會刪除該文件),然后保存。當(dāng)你保存這個文件時,Xcode會提供一個Objective-C橋接頭文件。如圖所示:
點擊Yes后,Xcode會創(chuàng)建橋接頭文件并且添加到你的工程中。Objective-C文件已經(jīng)用不上了,可以直接刪除。
打開新創(chuàng)建的"ParseTutorial-Bridging-Header.h"文件,添加以下內(nèi)容到文件底部:
- #import #import #import
接下來,你需要在Parse網(wǎng)站上API key供我們的app使用。在Parse Dashboard上打開你的app的Settings界面,在左邊的面板上選擇Keys按鈕。記下application ID和Client Key。
下一步,打開AppDelegate.swift文件,定位到application(_:didFinishLaunchingWithOptions:)。在該方法起始處添加如下內(nèi)容:
- Parse.setApplicationId("--AppID Goes Here--", clientKey: "--ClientKey Goes Here--")
當(dāng)然,需要在AppID和clientKey的位置要填入你之前記下的真實ID和Key。
Build后運(yùn)行App。如果沒有任何錯誤,意味著app已經(jīng)注冊并連接到Parse后臺。你已經(jīng)可以調(diào)用Parse相關(guān)的服務(wù)了。
下個步驟中,我們要創(chuàng)建一些示例對象。
#p#
創(chuàng)建示例對象
每個上傳的Parse對象都會成為訪問數(shù)據(jù)庫結(jié)構(gòu)的入口。你可以把這些對象看做是字典——事先存儲以關(guān)鍵字標(biāo)示的數(shù)據(jù),然后你就可以通過關(guān)鍵字取到對象。
在該例子中,你將上傳一個叫做“Player”的對象,包含“Name”和“Score”兩個字段。因此在數(shù)據(jù)庫中,將會有一個叫“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!)")
- }
- }
正如你看到的,上傳對象的代碼是異步的,你將在閉包中檢查到返回結(jié)果。
PFObject是Parse中的一個基類,它提供了一些基本的對象操作方法。***的好處是,你不需要在Parse網(wǎng)站上創(chuàng)建表,Parse會基于你提交的對象創(chuàng)建表結(jié)構(gòu)。
構(gòu)建,運(yùn)行。如果你正確放置了API key,且app正確注冊了Parse服務(wù),app應(yīng)該正常運(yùn)行。否則,你將收到錯誤信息。
等等,你的對象去哪了?只是漂浮在網(wǎng)絡(luò)空間嗎?
想要正確查看你保存的對象,只需要打開Parse的dashboard,點擊Core,你就能看到如下圖所示的對象:
恭喜你,你已經(jīng)成功的和網(wǎng)絡(luò)后臺進(jìn)行交互。
注意:如果你在iOS模擬器上運(yùn)行app,并看到錯誤信息如“The network connection was lost”。請嘗試重啟模擬器。其他的網(wǎng)絡(luò)錯誤也可以用這個方法試一下。
若你已經(jīng)獲得“Object Uploaded”消息,但在Dashboard上沒有看到數(shù)據(jù),請點擊右上方的“Refresh”按鈕刷新Dashboard頁面。
進(jìn)行下一步之前,先創(chuàng)建另外一條數(shù)據(jù)。設(shè)置name為“John”,score為810.現(xiàn)在你有兩條數(shù)據(jù),name都為John,但score不同。再添加第三條數(shù)據(jù),name為“Sally”, score為2400。
獲取對象
現(xiàn)在,我們嘗試一下獲取對象。Parse中有PFQuery類來支持這個功能。它可以執(zhí)行數(shù)據(jù)請求,你可以在 PFQuery documentation 中查看到更多資料。
讓我們來實現(xiàn)獲取符合如下條件的對象:
score大于1000,且name等于“John”,注釋掉(或刪除)之前的代碼,不然的話每次運(yùn)行都會上傳一個新的對象。然后放置如下代碼:
- // 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!)")
- }
- }
- 這里我們創(chuàng)建了數(shù)據(jù)請求的對象,class name即為表名。
- 通過whereKey方法,指定只獲取符合條件的對象(name為John,score大于1000)
- 發(fā)送請求,然后在閉包中打印結(jié)果。
再次構(gòu)建并運(yùn)行app,數(shù)據(jù)請求是異步的,因此不會對拖慢UI顯示的速度——這會使用戶更滿意。在控制臺中,你應(yīng)該會看到所有符合條件的對象,如圖所示:
現(xiàn)在我們已經(jīng)探索了存儲和獲取數(shù)據(jù)的基本操作,我們在真實項目里應(yīng)用一下。
記得先注釋掉application(_:didFinishLaunchingWithOptions:) 中我們剛寫的代碼。
用戶注冊
首先,用戶會使用我們的app注冊賬號。
打開RegisterViewController.swift, 當(dāng)前這個界面什么都干不了。我們的任務(wù)就是實現(xiàn)點擊“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)
- }
- }
- }
以上代碼中,按照如下步驟創(chuàng)建用戶:
- 創(chuàng)建PFUser對象,賦值給user。你將使用這個對象來完成登錄和注冊流程。它將存儲你的認(rèn)證用戶信息,這樣你就可以訪問該用戶的數(shù)據(jù)了。你可以通過該鏈接訪問PFUser的文檔:http://www.parse.com/docs/ios/api/Classes/PFUser.html
- 取得界面上username和password文本框的內(nèi)容,分別給user對象中相應(yīng)的字段賦值。
- 后臺調(diào)用注冊的方法,然后檢查返回值??赡苡袃煞N結(jié)果:返回正常證明已成功創(chuàng)建了用戶,并以該用戶的身份登錄;若有錯誤為創(chuàng)建失敗。創(chuàng)建成功后就直接跳轉(zhuǎn)到照片墻界面,否則則給出錯誤提示。
構(gòu)建、運(yùn)行app查看是否有錯誤。在Log In界面中,點擊Sign Up按鈕,你將看到如下界面:
輸入用戶名、密碼,點擊Sign Up 按鈕,若一切正常的話你將跳轉(zhuǎn)到照片墻界面。
不錯,不過保險起見,我們還是驗證一下新用戶是否真的已經(jīng)在表中創(chuàng)建成功:Dashboard中打開User選項,如下所示:
恭喜!你已經(jīng)創(chuàng)建了***個用戶?,F(xiàn)在讓我們用這個用戶登錄,在做些有意思的事情。
登錄
打開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)
- }
- }
- }
流程非常簡單。跳轉(zhuǎn)到下個界面前,我們首先要檢查用戶名和密碼是否能和數(shù)據(jù)庫中的記錄匹配。
構(gòu)建、運(yùn)行程序,效果如下:
嘗試用我們創(chuàng)建的用戶登錄,如果一切正常,app將會跳轉(zhuǎn)到照片墻界面。保險起見,可以嘗試用錯誤的用戶名或密碼來登錄,看是否有錯誤代碼顯示。
#p#
發(fā)送照片到照片墻
之前的注冊、登錄操作都會跳轉(zhuǎn)到照片墻視圖。在這個視圖中,你會看到所有用戶上傳的圖片和評論。
在那之前,我們得先上傳一些圖片。
使用Parse上傳文件很簡單。打開UploadImageViewController.swift,我們將在這個類中實現(xiàn)上傳功能。
所有用戶登錄后都可以點擊“Upload”按鈕跳轉(zhuǎn)到上傳視圖。
在這里,用戶可以選擇輸入備注并點擊“Select Picture”,使用系統(tǒng)標(biāo)準(zhǔn)的image picker從照片庫中獲取照片,上傳。
所有上述代碼已經(jīng)在起始工程中實現(xiàn),現(xiàn)在我們需要實現(xiàn)sendPressed(_:)代碼。這個action方法連接到導(dǎo)航欄的“Send”按鈕上。它將照片和備注發(fā)送到服務(wù)器上。
該過程包含兩個部分,一是使用PFFile對象上傳圖片,二是將其添加到PFObject,并上傳至服務(wù)器。
之前我們已經(jīng)看到,可以使用setKey和objectForKey方法添加和獲取PFObject的字段。但現(xiàn)在我們需要用到特定的對象類型(照片墻),這時,自定義的子類可以更好的發(fā)揮作用。接下來你會看到如何實現(xiàn)。
自定義Parse對象
打開Model group下的WallPost.swift文件。當(dāng)前你會看到繼承自NSObject類的簡單類。首先,修改父類,使其繼承自PFObject:
- class WallPost: PFObject {
- }
你還需要WallPost類遵循PFSubclassing協(xié)議。
PFSubclassing協(xié)議 定義了一些繼承PFObject的必要方法。PFObject+Subclass.h中定義的category實現(xiàn)了這些方法,你需要做的是在自己的子類中重寫它們。
具體做法是在WallPost類中添加擴(kuò)展,擴(kuò)展中包含這兩個必要方法:
- 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()
- }
- }
- }
- 按照后臺數(shù)據(jù)庫的記錄設(shè)置類名。
- 讓Parse知道:所有類的類型為WallPost的對象,都將使用該子類。這個方法只應(yīng)被調(diào)用一次,因此我們使用dispatch_once_t方法。
接下來,我們?yōu)閃allPost類添加三個屬性:
- @NSManaged var image: PFFile
- @NSManaged var user: PFUser
- @NSManaged var comment: String?
這里,我們用PFFile類型的image放置上傳用的照片,PFUser類型的user保存用戶信息,還有String類型的comment保存照片備注。
我們使用了@NSManager,因為從底層角度來看,PFObject的屬性只是一些鍵值對參數(shù)的集合。當(dāng)我們設(shè)置某一個屬性的時候,會自動被作為鍵值對設(shè)置。
另外,在子類中我們需要定義一個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
- }
以下是這段代碼的詳細(xì)說明:
- 為WallPost類創(chuàng)建PFQuery對象。
- 調(diào)用該方法以返回完整的user信息。若沒有這句,該query只會返回當(dāng)前對象的引用,而不包含任何成員的信息。
- 按照創(chuàng)建日期排序。
***,我們需要添加初始化方法。
- init(image: PFFile, user: PFUser, comment: String?) {
- super.init()
- self.image = image
- self.user = user
- self.comment = comment
- }
- override init() {
- super.init()
- }
以上就是一個簡單的初始化方法,不管是否給定初始值,都可以創(chuàng)建一個WallPost對象。
WallPost已經(jīng)完成,讓我們繼續(xù)上傳照片的工作。
打開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)%")
- })
以下是詳細(xì)說明:
- 使用image data創(chuàng)建PFFile對象,然后在后臺執(zhí)行保存動作。
- 如果成功,保存文件相關(guān)PostWall對象。
- 如果不成功,告知用戶。
- 保存文件時,Parse支持跟蹤保存進(jìn)度。通過progress block即可得知當(dāng)前進(jìn)度。這里我們只是簡單的把進(jìn)度打印到控制臺。
接下來實現(xiàn)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!)
- }
- }
- }
- }
詳細(xì)說明如下:
- 根據(jù)上傳圖片、當(dāng)前已登錄用戶和圖片備注創(chuàng)建WallPost對象。
- 后臺保存WallPost對象。
- 如果成功,返回照片墻。
- 否則,告知用戶。
構(gòu)建、運(yùn)行app。登錄之前創(chuàng)建的用戶,進(jìn)入圖片上傳界面,點擊“Select Picture”按鈕,從照片庫中選擇一張圖片,然后隨便寫一條備注,點擊“Send”按鈕。
在控制臺上你可以看到上傳的百分比。這里只是將其顯示在控制臺上,在最終版的app中,使用該進(jìn)度顯示一個progress bar更合適。
在Dashboard上,查看Core數(shù)據(jù),你將會看到一個新的表,名為WallPost。不錯,但是唯一的不足是你沒有辦法在app上看到上傳的照片。
那么我們下一步就來實現(xiàn)取回照片的功能。
#p#
在照片墻上展示照片
打開WallPicturesViewController.swift,該視圖將會顯示所有用戶上傳的照片。當(dāng)該視圖加載時,它會調(diào)用getWallImages()方法來獲取所有對象,當(dāng)前其為空。
要是其可以工作,我們得先添加一些代碼,在獲取照片后放置它們在照片墻。添加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對象.然后我們使用快速枚舉的方法遍歷數(shù)組中的對象,針對每一個對象,執(zhí)行以下步驟:
- 創(chuàng)建一個視圖來顯示圖片和詳情。
- 下載圖片數(shù)據(jù)。
- 添加圖片視圖到照片墻。
- 獲取上傳圖片的用戶的信息,將創(chuàng)建日期放置在label上。
- 添加包含備注信息的label。
- 將上述界面元素放置到scroll view上,并且增加用以指示下個顯示位置的坐標(biāo)。
- 設(shè)置scrollview的content size。
現(xiàn)在,替換getWallImages()方法的內(nèi)容:
- 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)
- }
- }
- }
詳細(xì)說明:
- 創(chuàng)建一個簡單的query 對象來獲取WallPost對象,并將結(jié)果按照創(chuàng)建日期排序。
- 查找到符合條件的對象。這里,即為WallPost對象。如果一切正常,則在照片墻上加載圖片。
- 如果有錯誤的話,提示用戶。
構(gòu)建、運(yùn)行app。你將看到之前上傳的圖片和備注信息?;c時間玩一下,再多添加些圖片和備注。然后在照片墻上看看。
很酷,不是嗎?
Parse UI
之前提過,還有另外一種展示保存圖片的方法。接下來我們看一下這種方法。
前面的例子中,我們使用了一個簡單的UIScrollView對象來展示圖片,這需要我們自己來計算content size。你可能想過使用UITableView可能更好,當(dāng)然,聰明的Parse開發(fā)者早就考慮到了,因此,它們編寫了ParseUI.framework,提供了很多方便的東西來顯示Parse相關(guān)的UI。
我們主要看看以下三個:
- PFQueryTableViewController:這是UITableViewController的子類??梢杂脕砗芊奖愕脑趖able view中顯示PFQuery的結(jié)果。
- PFTableViewCell:UITableViewCell的子類,和PFQueryTableViewController搭配使用。
- PFImageView:UIImageView的子類,包含管理下載和顯示Parse圖片的功能。
現(xiàn)在,打開WallPicturesTableViewController.swift將它的父類從UITableViewController 修改為PFQueryTableViewController。
當(dāng)然,WallPostTableViewCell也要繼承自PFTableViewCell,其中的postImage對象的類型也要改為PFImageView。
編寫代碼之前,我們需要對storybaord做些修改。打開Main.storyboard,找到WallTableView scene:
打開屬性查看器(Attributes Inspector),你會看到一個包含PFQueryTableViewController參數(shù)的選項:
這些參數(shù)可以讓你選擇顯示在table上的對象類型。并且可以指定下拉刷新、分頁和loading界面。當(dāng)使用簡單的UITableview來展示結(jié)果時,你甚至可以設(shè)置table中要顯示的PFObject字段的key,而不需要動手在代碼中去設(shè)置。在Parse Class的參數(shù)中,填入WallPost。
現(xiàn)在回到WallPicturesTableViewController.swift文件,添加以下方法:
- override func viewWillAppear(animated: Bool) {
- loadObjects()
- }
- override func queryForTable() -> PFQuery {
- let query = WallPost.query()
- return query!
- }
每次顯示照片墻界面,我們都希望它被重新加載。為了指定運(yùn)行的請求,我們重寫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查找對應(yīng)的對象。
我們來看一下具體的代碼解釋:
- 從table view中dequeue出一個cell對象,轉(zhuǎn)換成WallPostTableViewCell類型。
- 轉(zhuǎn)換PFObject對象為WallPost類型。
- 調(diào)用PFImageView的loadInBackground方法,下載圖片。在complete closure中記錄下載進(jìn)度。這里你需要將這個進(jìn)度顯示在UIProgressBar上。
- 添加創(chuàng)建日期、用戶名和備注到cell上。
運(yùn)行代碼前,還有***一個步驟.打開LoginViewController.swift,在loginPressed(_:)方法中,將scrollViewWallSegue替換為tableViewWallSegue。在RegisterViewController.swift中,也進(jìn)行同樣的替換,這樣就可以正常跳轉(zhuǎn)到新版本的照片墻視圖。
構(gòu)建、運(yùn)行app, 你會看到照片墻顯示在table view上,圖片下載時,還能看到進(jìn)度條更新進(jìn)度。
#p#
保持登入、登出
你應(yīng)該已經(jīng)意識到,每次app啟動時,用戶都需要重新登錄。另外,"Log Out"按鈕每次只是將用戶帶到主界面,而沒有實際的登出功能。
在教程的***,我們將添加記住登錄狀態(tài)的功能,即使app重新啟動,登錄狀態(tài)也會保持。另外,我們還會添加真正的登出功能。
打開LoginViewController.swift,添加以下代碼到viewDidLoad()方法中:
- //Check if user exists and logged in
- if let user = PFUser.currentUser() {
- if user.isAuthenticated() {
- self.performSegueWithIdentifier(scrollViewWallSegue, sender: nil)
- }
- }
當(dāng)用戶登錄后,Parse將會在app重啟時記錄用戶和狀態(tài)。這里我們用可選值綁定(if let)檢查當(dāng)前是否存在用戶。如果存在,我們檢查用戶是否已認(rèn)證,若已認(rèn)證,證明用戶已登錄,直接跳轉(zhuǎn)到照片墻視圖。
要登出用戶,打開WallPicturesTableViewController.swift, 找到logOutPressed(_:)方法,添加以下代碼:
- @IBAction func logOutPressed(sender: AnyObject) {
- PFUser.logOut()
- navigationController?.popToRootViewControllerAnimated(true)
- }
這里我們簡單地登出當(dāng)前用戶,并跳轉(zhuǎn)到初始的登錄界面。記得在WallPicturesViewController.swift中添加同樣的登出代碼。
構(gòu)建、運(yùn)行,大功告成!
下一步做什么?
這個鏈接包含了完整的實例工程:http://cdn4.raywenderlich.com/wp-content/uploads/2015/04/ParseTutorial-Finished.zip
你已經(jīng)看到了使用PFObject子類上傳、下載對象是如何便利。也學(xué)到了在Parse使用PFUser的方法。
使用Parse可以完成更多的工作。Parse還支持在app內(nèi)部給你的用戶發(fā)送推送通知。還有更多的社交功能已經(jīng)集成到framework中。你也可以添加數(shù)據(jù)分析記錄用戶行為。
Parse提供更多高級特性,例如編寫云端代碼,在后臺安排可循環(huán)執(zhí)行的計劃任務(wù)。
在你編寫Parse app的過程中,你會更加了解它。本人強(qiáng)烈推薦你探索更多高級的特性。
現(xiàn)在,對于添加后臺功能這件事,你應(yīng)該已經(jīng)信心十足了。如何創(chuàng)建一個云端應(yīng)用,現(xiàn)在已經(jīng)不是一件高不可攀的事情了。
希望看到你做出更多基于Parse的app。如果有任何問題或建議,請加入論壇,一起討論。