精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

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適配后臺

2014-05-04 13:47:39

銳捷網絡極簡網絡

2010-06-11 13:53:54

UML建模

2011-08-10 15:48:10

iPhone網絡

2021-11-22 08:50:20

Kubernetes網絡策略云原生應用程序

2011-06-02 10:28:11

網絡命令

2018-11-28 14:30:49

權限系統數據

2021-07-14 10:29:30

REvil勒索軟件基礎設施

2011-07-21 10:17:53

java

2017-12-12 07:47:59

dockermarathon服務器

2009-07-22 13:32:43

iBATIS DAO

2017-07-18 10:14:23

OracleMerge into教程

2020-10-17 09:48:55

Spinnaker實踐

2011-07-18 09:35:29

iPhone 框架

2011-03-14 14:13:28

網絡故障

2011-06-02 10:28:18

2011-06-27 09:47:43

點贊
收藏

51CTO技術棧公眾號

亚洲欧美一区二区三区极速播放| 成人综合久久| 日韩欧美中文免费| 日韩欧美一区二区三区久久婷婷| 97超碰中文字幕| 亚洲午夜精品久久久久久app| 日韩电影免费观看中文字幕| 日本人69视频| 男人天堂视频在线观看| 中文欧美字幕免费| 国产一区二区精品免费| 亚洲 国产 日韩 欧美| 欧美激情在线| 中文字幕视频在线免费欧美日韩综合在线看| 欧美性猛交xxxx乱大交91| 麻豆网站免费在线观看| 亚洲欧洲制服丝袜| 日本一区二区三区视频在线观看| 国产福利视频导航| 奇米精品一区二区三区在线观看| 午夜免费日韩视频| 国产精品夜夜夜爽阿娇| 一区二区美女| 精品sm在线观看| 天堂中文av在线| 日韩国产网站| 欧美网站在线观看| 日韩人妻无码精品久久久不卡| 1区2区3区在线观看| 99久久精品免费看| 99爱精品视频| 一区二区 亚洲| 日韩 欧美一区二区三区| 97视频在线观看免费| 日韩女优一区二区| 欧美疯狂party性派对| 亚洲天堂开心观看| 中文在线永久免费观看| 澳门久久精品| 欧美一级久久久久久久大片| 蜜臀一区二区三区精品免费视频 | h视频久久久| 欧美日韩免费一区二区三区 | 亚洲欧美日韩综合一区| 欧美男男同志| 91热门视频在线观看| 国产91精品一区二区绿帽| 国产绿帽一区二区三区| 久久99国产精品成人| 国产精品普通话| 免费看污视频的网站| 另类激情亚洲| 日本精品va在线观看| 全部毛片永久免费看| 亚洲人成久久| 2020国产精品视频| 毛片在线免费视频| 久久精品女人天堂| 国产成人av在线播放| 亚洲欧美偷拍一区| 久久久久中文| 国产精品第1页| 中文字幕+乱码+中文乱码91| 日韩中文欧美在线| 国产精品美女在线观看| 亚洲一区二区人妻| 激情另类小说区图片区视频区| 成人黄色在线免费| 亚洲第一色网站| 99精品在线免费| 国产成人久久精品| 欧美裸身视频免费观看| 国产视频一区二区三区在线播放| 色是在线视频| 欧美性一级生活| 中文字幕亚洲欧洲| 麻豆精品久久| 亚洲精品456在线播放狼人| a天堂视频在线观看| 天美av一区二区三区久久| 亚洲日本成人女熟在线观看| 少妇愉情理伦三级| 一区二区日韩欧美| 91国内在线视频| 中文字幕+乱码+中文乱码www| 激情小说亚洲一区| 国产三区二区一区久久| 不卡在线视频| 亚洲欧美二区三区| 精品无码国模私拍视频| 精品123区| 91精品国产高清一区二区三区蜜臀 | 一二三四在线观看视频| 中文在线播放一区二区| 久久免费在线观看| 国产精品高清无码| 成人丝袜视频网| 青青草原成人| sm国产在线调教视频| 天天影视网天天综合色在线播放| 精品免费国产一区二区| 看亚洲a级一级毛片| 亚洲精品中文字幕av| 精品在线观看一区| 亚洲一区日韩| 91在线视频精品| 精品三级久久久久久久电影聊斋| 亚洲欧洲国产日本综合| 国产黄色特级片| 日本免费精品| 中文字幕欧美专区| 欧美国产成人精品一区二区三区| 精品一二三四区| 欧美精品亚洲精品| 啦啦啦中文在线观看日本| 在线观看免费一区| 国产 中文 字幕 日韩 在线| 亚洲精品小说| 国产精品视频自拍| 手机亚洲第一页| 亚洲最大成人网4388xx| 成年人三级黄色片| 欧美一站二站| 国产不卡在线观看| 免费黄网站在线观看| 五月天久久比比资源色| 91精产国品一二三| 欧美福利在线| 国产精品亚洲网站| 成年人在线视频| 一本一道波多野结衣一区二区| 亚洲一区二区三区四区av| 91精品久久久久久久蜜月| 国产精品美乳在线观看| 你懂的在线网址| 欧美日韩中文字幕综合视频| 北京富婆泄欲对白| 在线播放日韩| 福利视频一区二区三区| 污网站在线免费看| 6080国产精品一区二区| 五月天免费网站| 日本成人在线不卡视频| 色视频一区二区三区| 成人在线爆射| 国产一区二区三区在线视频| 国产一区二区视频免费| 国产午夜精品在线观看| 一本久道综合色婷婷五月| 色综合综合色| 国产精品第一页在线| 激情综合闲人网| 91久久精品一区二区三区| 一级肉体全黄裸片| 免费成人美女在线观看| 一本一道久久a久久精品综合| 另类一区二区三区| 久久视频免费在线播放| 精品人妻少妇嫩草av无码专区| 亚洲精品菠萝久久久久久久| 乳色吐息在线观看| 韩日欧美一区| 国产伦精品一区二区三毛| 爱福利在线视频| 亚洲精品久久视频| 亚洲图片在线视频| 中文一区一区三区高中清不卡| 在线观看国产一级片| 五月婷婷亚洲| 国产乱码精品一区二区三区中文| 国产剧情av在线播放| 亚洲欧洲高清在线| 国产精品久久久久久久成人午夜| 亚洲精品视频免费观看| 成年人的黄色片| 天堂影院一区二区| 亚洲激情一区二区三区| 99久久这里有精品| 69久久夜色精品国产69乱青草| 欧美日韩伦理片| 欧美高清一级片在线| 欧美日韩在线观看成人| 99re8在线精品视频免费播放| 成人性生生活性生交12| 午夜精品视频| 欧美日韩精品免费观看| 亚洲精品成a人ⅴ香蕉片| 久久久久在线观看| 国产精品四虎| 欧美videos中文字幕| 自拍偷拍18p| 一区二区三区中文字幕| 久久精品成人av| 国产在线麻豆精品观看| 欧美黄网站在线观看| 五月综合激情| 欧美一级爱爱| 亚洲精品影片| 国产精品免费在线免费| 91在线三级| 日韩在线欧美在线| 三级做a全过程在线观看| 666欧美在线视频| 久久久久久不卡| 亚洲一区二区视频在线| 五月婷婷欧美激情| 成人免费视频一区| 想看黄色一级片| 日韩一区精品字幕| 久久久久久久久久网| 国产精品99一区二区三区| 久久精品成人一区二区三区蜜臀| 四虎国产精品成人免费影视| 欧洲一区二区视频| 免费网站在线观看人| www.99久久热国产日韩欧美.com| 亚洲欧美丝袜中文综合| 日韩精品一区二区三区三区免费| 亚洲性猛交富婆| 色呦呦日韩精品| 人人干人人干人人干| 一区二区三区不卡视频| 欧美一区二区三区观看| 久久午夜老司机| 精品少妇人妻av一区二区三区| 激情久久五月天| 无尽裸体动漫2d在线观看| 日韩精品1区2区3区| 高清在线观看免费| 日韩亚洲国产欧美| www.在线观看av| 欧美日韩国产高清| 少妇高潮流白浆| 国产精品二区不卡| 一区二区三区四区视频在线| 精品国产乱码久久久久久蜜坠欲下 | 中文字幕免费不卡| 久久成人激情视频| 久久久精品人体av艺术| 三级黄色片网站| proumb性欧美在线观看| 50一60岁老妇女毛片| 成人妖精视频yjsp地址| 黄色av电影网站| 北岛玲一区二区三区四区 | 2欧美一区二区三区在线观看视频| 性猛交╳xxx乱大交| 国产成人99久久亚洲综合精品| 视频区 图片区 小说区| 国产二区国产一区在线观看| 国产不卡的av| 国产精品亚洲视频| 亚洲AV无码久久精品国产一区| 黄页网站大全一区二区| 国产男女无遮挡猛进猛出| 丁香五精品蜜臀久久久久99网站 | 免费在线观看毛片网站| 久久只有精品| 亚洲欧美日本一区二区三区| 国产一区二区三区观看| 性色av浪潮av| 白白色亚洲国产精品| 免费在线观看你懂的| 国产视频一区不卡| 国产精品麻豆免费版现看视频| 国产精品激情偷乱一区二区∴| 深夜福利影院在线观看| 午夜激情久久久| 老熟妇一区二区三区| 在线电影一区二区三区| 高h放荡受浪受bl| 亚洲美女性视频| 欧美极品另类| 欧美激情极品视频| 666av成人影院在线观看| 国产欧美中文字幕| 91精品尤物| 欧美激情第六页| 欧美aaaa视频| www.欧美黄色| 日韩电影在线观看网站| 中文字幕av一区二区三区人妻少妇| av电影一区二区| 成人性视频免费看| 亚洲午夜国产一区99re久久| 日韩免费av网站| 日韩欧美综合一区| 毛片免费在线| 精品少妇一区二区30p| 最近高清中文在线字幕在线观看1| 国产精自产拍久久久久久蜜| 日韩激情精品| 日韩欧美三级一区二区| 欧美日韩国产亚洲一区| 蜜臀久久99精品久久久酒店新书| 国产麻豆精品一区二区| caopeng视频| 一区二区在线观看视频| 波多野结衣mp4| 欧美成人三级在线| 香蕉视频国产在线观看| 97在线观看免费高清| 色999韩欧美国产综合俺来也| 国产自产精品| 天天av综合| 天天碰免费视频| 成人精品国产一区二区4080| 来吧亚洲综合网| 色综合久久88色综合天天6| 成人免费视频国产| 日韩中文字在线| 亚洲高清黄色| 国产精品二区三区四区| 久久久久国产精品| 美女网站免费观看视频 | 黄色裸体一级片| 欧美午夜久久久| 精品人妻一区二区三区麻豆91 | 色婷婷精品国产一区二区三区| av成人黄色| 国产日韩视频一区| 亚洲精品免费电影| 国产精品人妻一区二区三区| 中文字幕成人精品久久不卡| 最新欧美色图| 久久久综合香蕉尹人综合网| 亚洲精品视频啊美女在线直播| av在线天堂网| 樱花草国产18久久久久| 国产精品一品二区三区的使用体验| 亚洲午夜未删减在线观看 | 1024在线看片你懂得| 亚洲综合精品伊人久久| 偷拍欧美精品| 久久久久久综合网| 17c精品麻豆一区二区免费| 亚洲一卡二卡在线| 丝袜美腿精品国产二区| 国产精品第一| 亚洲国产精品毛片| 奇米精品一区二区三区在线观看一 | 国产精品你懂的在线| 免费看污视频的网站| 亚洲视频专区在线| 日韩高清在线| 亚洲欧洲另类精品久久综合| 另类综合日韩欧美亚洲| 影音先锋男人看片资源| 6080亚洲精品一区二区| 最新日本在线观看| 超碰97人人在线| 亚洲黄色av| 最近日本中文字幕| 欧美视频在线观看免费| 黄色国产在线| 国产美女被下药99| 重囗味另类老妇506070| 婷婷五月精品中文字幕| 高跟丝袜欧美一区| 国产青青草在线| 国产成人精品免高潮在线观看| re久久精品视频| 午夜精品免费看| 亚洲午夜影视影院在线观看| 人妻91麻豆一区二区三区| 欧美亚洲在线观看| 成人黄色小视频| 男人女人拔萝卜视频| 精品美女国产在线| 成人欧美一区| 亚洲一区二区三区在线视频| 亚洲国产国产亚洲一二三| 女~淫辱の触手3d动漫| 欧美日韩国产免费| 狂野欧美性猛交xxxxx视频| 欧美精品与人动性物交免费看| 日本美女一区二区| 欧美久久久久久久久久久久| 日韩电视剧免费观看网站| 成人av集中营| 日韩一级性生活片| 国产精品视频观看| 亚洲免费成人网| 国产成人亚洲精品| 午夜久久久久| 亚洲自拍偷拍图| 日韩美一区二区三区| 中文字幕在线直播| 永久免费看av| 国产片一区二区三区| 亚洲av无码一区二区乱子伦| 国产999在线观看| 国产精品国码视频| 天堂网av2018| 亚洲免费电影一区| 综合激情五月婷婷| 日韩不卡一二三| 99热国内精品| 久久视频在线看| 久久无码精品丰满人妻|