本文由CocoaChina翻譯組成員leon(社區ID)翻譯自raywenderlich
原文:Parse Tutorial: Getting Started with Web Backends
網絡後台支持可以為你的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相關的服務了。
下個步驟中,我們要創建一些示例對象。
創建示例對象
每個上傳的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!)") } }
1. 這裡我們創建了數據請求的對象,class name即為表名。
2. 通過whereKey方法,指定只獲取符合條件的對象(name為John,score大於1000)
3. 發送請求,然後在閉包中打印結果。
再次構建並運行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) } } }
以上代碼中,按照如下步驟創建用戶:
1. 創建PFUser對象,賦值給user。你將使用這個對象來完成登錄和注冊流程。它將存儲你的認證用戶信息,這樣你就可以訪問該用戶的數據了。你可以通過該鏈接訪問PFUser的文檔:http://www.parse.com/docs/ios/api/Classes/PFUser.html
2. 取得界面上username和password文本框的內容,分別給user對象中相應的字段賦值。
3. 後台調用注冊的方法,然後檢查返回值。可能有兩種結果:返回正常證明已成功創建了用戶,並以該用戶的身份登錄;若有錯誤為創建失敗。創建成功後就直接跳轉到照片牆界面,否則則給出錯誤提示。
構建、運行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將會跳轉到照片牆界面。保險起見,可以嘗試用錯誤的用戶名或密碼來登錄,看是否有錯誤代碼顯示。
發送照片到照片牆
之前的注冊、登錄操作都會跳轉到照片牆視圖。在這個視圖中,你會看到所有用戶上傳的圖片和評論。
在那之前,我們得先上傳一些圖片。
使用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() } } }
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:
打開屬性查看器(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查找對應的對象。
我們來看一下具體的代碼解釋:
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。如果有任何問題或建議,請加入論壇,一起討論。