原文地址:http://blog.csdn.net/vipwangl/article/details/8846415
最近在學習Parse,但是Parse的中文教程比較少,看到這篇英文教程,把它翻譯一下與大家共享,本人的英語水平不是很高,有的地方可能譯得不好,望大神輕拍。。
原文地址http://www.raywenderlich.com/19341/how-to-easily-create-a-web-backend-for-your-apps-with-parse
首先—創建你的后台服務
在開始編寫你的app前,你首先要做的是創建你的Parse后台,每個開發人員和每個app都需要一個不同的標識,否則你的數據和賬號會和別人的混淆,雖然這會帶來一些有趣的副作用,但是你應該使你的數據和別人的區別開來。
第一步就是訪問Parse.com,然后在右上角點擊Sign Up創建一個新賬號。
賬號創建好后,你會被要求創建你的第一個app,每個你想要使用后台服務的應用都要單獨地注冊。在這里,我們把這個應用命名為“tutorialApp”;在Parse中可能存在着很多同名的app,但是你注冊的只有一個。
你的app創建好后,來到Dashboard頁面,在這里你可以查看你app的數據,這里有一系列的操作按鈕,有點像UISegmentedControl,如以下截圖:
這里是對屏幕上方一些操作按鈕的說明:
- Overview:在這里你可以看到一些關於你app統計信息,如流量,推送信息,調用API的次數等。
- Data Browser:這里你可以看到所有放到你后台里的數據。你也可以看到賬號,你可以手動地操作數據,這里就像一個數據庫編輯器。
- Push Notifications:可以在這里向你的用戶發送推送信息,或者向一個特定組發送推送信息。
- Setting:你可以在這里設置你的app,管理它的安全性,和導出你的數據。
Parse示例項目
為了在這篇教程中創建一個后台服務,這里提供了一個簡單的項目來使大家容易入手。你可以下載它並跟着本教程添加Parse服務。示例項目就放在github上。
你可以在https://github.com/toniomg/TutorialBase上下載這個項目,也可以使用以下終端命令:
- git clone https://github.com/toniomg/TutorialBase
在Xcode中打開這個項目,編譯運行!首先你會看到一個登陸界面,但目前為止,這個項目還沒有加入后台服務,你很快就會完成這些功能。
在繼續學習之前,先打開MainStoryboard.storyboard來看一下程序的結構和流程。
這個項目分為4個主要的視圖,每個視圖在storyboard中都有自己的視圖控制器和視圖
- Log In:登陸頁面有用戶名和密碼文本框,還有一個Sign Up按鈕,在你想注冊一個新賬號的時候用來前往Sign Up頁面。
- Sign Up:在這個視圖,用戶輸入用戶名和密碼,用來在后台服務中創建一個新賬號。
- Wall:這是這個app中的主要界面,這里用戶可以看到其他用戶上傳的帶有評論的圖片。
- Upload:在這里,用戶可以上傳帶有評論的圖片到照片牆上。
注意segue線表示了這個app的流向,包括繞過了Sign Up界面的流向。如下圖所示:
准備Parse服務
第一步自然是要配置你的項目使它可以加入Parse服務!
在這個地址下載Parse框架:https://parse.com/downloads/ios/parse-library/latest
下載完框架后,解壓並把Parse.framework文件夾拖入你的Xcode項目的Framework文件夾內。記得勾選“Copy item...”和“Create groups...”。
默認下Parse框架會加入到“tutorialBase”中,這也是我們期望的,然后添加其他的框架,完成后的框架列表如下:
(怎么添加框架的步驟就不說了,網上一大把)
下一步就是在app啟動時注冊后台服務,在AppDelegate.m文件中加入頭文件:
- #import <Parse/Parse.h>
然后,在函數didFinishLaunchingWithOptions的開頭,加入語句:
- [Parse setApplicationId:AppID clientKey:clientKey];
你會看到有錯誤出現了,Application ID和Client Key需要一個常量,但是它們現在還是空的——是時候改正了!
為了找到需要的API keys,要去到Parse Dashboard(1),選擇你的app(2),然后找到左側欄,復制Application ID和Client Keys(3),如下圖所示:
(注意,我看到的界面與上圖有的不同,我是在Settings——Application keys界面中找到所需的App ID和Client Key的)
你可以直接把keys復制到setApplicationId方法中,它們只需使用一次。完成后,這個方法看起來和下面代碼是相似的,只是keys有所不同:
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- // Register our parse app with the service
- [Parse setApplicationId:@"UXuHVmNRX44rcczbv1NIIHHbazteYfQU4GAJ8EOS"
- clientKey:@"cqFwq5Vpb19VKPKSe1dOZJrjsQbytPzKa2bEdakx"];
- return YES;
- }
編譯運行你的app!確定沒有任何錯誤。一切順利的話,意味着你的app已經綁定Parse后台服務了。你即將開始使用后台服務!
下一步就是創建一些示例對象!
創建示例對象
現在你的項目已經配置好了並連接上Parse,現在花一點時間來復習一下發送對象到后台和從后台獲取對象的概念。
你可以根據之前的步驟創建一個新的項目,或者在示例項目中交替地使用AppDelegate文件。
在這個例子中,你會使用PFObject類,這是一個基本的類,提供一些基本的對象操作方法。對於PFObject類的詳細詳細,你可以參照這個文檔:https://parse.com/docs/ios/api/Classes/PFObject.html。
在示例中,你會上傳一個叫“Player”的對象,這個對象有“Name”和“Score”字段。在你的數據庫中,你會有一個名為“Player”的表,和你上傳的所有對象,下面來看看例子:
找到didFinishLaunchingWithOptions方法,之后添加以下代碼,連接到Parse后台服務:
- PFObject *player = [PFObject objectWithClassName:@"Player"];//1
- [player setObject:@"John" forKey:@"Name"];
- [player setObject:[NSNumber numberWithInt:1230] forKey:@"Score"];//2
- [player save];//3
注釋1:在這一行你創建了一個類名為“Player”的對象。
注釋2:在這里你對字段賦上值,name字段的值為“John”,score字段的值為“1230”。
注釋3:在這里你保存了對象,對象會同步發送到Parse服務器。
這就可以了!最厲害的是你無須在瀏覽器上的Parse界面去創建一個表,這個表將根據你上傳的對象自動創建。
編譯運行你的程序!如果你正確地在代碼中設置了keys,還有你的app在上傳對象前正確注冊到了Parse服務器,那么一切都會很順利。
但上傳的對象在哪?
為了檢查你的對象是否正確保存了,在瀏覽器中打開Parse dashboard界面,點擊“Data Browser”,在這里你應該可以看到你上傳的對象,如下圖:
這就是保存對象最簡單的方法。恭喜你成功地和后台進行了交互!
異步操作
你可能已經注意到了,在控制帶出現了警告信息,你的app會被阻塞直到你的對象完成上傳,這是同步的網絡操作!這樣你不但不能檢查調用的結果,你的用戶也會被卡在調用API的等待上。
你的應用可能會因此獲得一星評分!當然,還是有解決的辦法的。
注釋掉之前在didFinishLaunchingWithOptions方法添加的代碼,否則你的app在每次運行時都會上傳一個新的對象。再添加以下的代碼:
- PFObject *anotherPlayer = [PFObject objectWithClassName:@"Player"];
- [anotherPlayer setObject:@"Jack" forKey:@"Name"];
- [anotherPlayer setObject:[NSNumber numberWithInt:840] forKey:@"Score"];
- [anotherPlayer saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
- if (succeeded){
- NSLog(@"Object Uploaded!");
- }
- else{
- NSString *errorString = [[error userInfo] objectForKey:@"error"];
- NSLog(@"Error: %@", errorString);
- }
- }];
正如你所看到,你使用了異步的方式上傳了對象,還有在一個代碼塊中檢查返回結果。隨着代碼塊在iOS中越來越多的使用,你應該對代碼塊感到熟悉。每個簡單的UIView動畫目前都是在代碼塊中完成的。幸運的是,這里有一個教程讓你更加熟悉代碼塊這種特性,鏈接為How To Use Block in iOS 5 Tutorial - Part 1(英文教程)。
編譯運行你的app吧!
在Parse Dashboard中檢查你是否正確上傳了對象到服務器。不同的是這次你的app在上傳對象時不會阻塞了。
你應該會注意到你的設備(或模擬器)會出現一個網絡活動指示器,指示器旋轉時登陸界面會彈出來。過了一會兒,當交互完成后,你會看到控制台中出現NSLog消息。當要上傳想image那種要花更長時間去傳輸的對象時,這是十分有用的。
像之前那樣,去到Data Browser界面你就會看到,在通過同步上傳的對象的旁邊出現了一個通過異步上傳的對象。
取得對象
現在,是時候去獲取對象了。為了實現這個目的,Parse有一個類PFQuery——它執行查詢操作,具體可看PFQuery documentation。
你將會編寫代碼,去查詢Score超過1000,Name為“John”的對象。在這之前,注釋掉之前的代碼,否則每次運行程序都會上傳新的對象。加入以下代碼:
- PFQuery *query = [PFQuery queryWithClassName:@"Player"]; //1
- [query whereKey:@"Name" equalTo:@"John"];//2
- [query whereKey:@"Score" greaterThan:[NSNumber numberWithInt:1000]]; //3
- [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {//4
- if (!error) {
- NSLog(@"Successfully retrieved: %@", objects);
- } else {
- NSString *errorString = [[error userInfo] objectForKey:@"error"];
- NSLog(@"Error: %@", errorString);
- }
- }];
注釋1:你創建了一個查詢對象,“Player”是你想進行查詢的表。
注釋2:你只想獲取name為“John”的對象。。。
注釋3:。。。還有score要超過1000的
注釋4:發送查詢,在代碼塊中打印結果。
編譯運行你的app!由於操作是異步的,你的UI界面不會卡住——這是讓你的用戶感到高興的關鍵。在控制台中,你會看到符合查詢條件的所有對象,如下圖所示:
在對基本的存儲和查詢操作有了簡單探索后,你可以繼續在項目中操作了。
回到項目中,注釋掉剛才的代碼。
用戶注冊
你的用戶使用你的app時的第一步就是在注冊賬號。
在項目中打開RegisterViewController.m文件,添加以下Parse頭文件:
- #import <Parse/Parse.h>
正如你所看到的,現在注冊視圖除了打開和關閉外,還沒有添加任何功能。你的任務就是在用戶點擊“Sign Up”按鈕時,可以進行注冊操作。
為了實現這個目的,你可以找到關聯了這個按鈕的IBAction:
- //Sign Up Button pressed
- -(IBAction)signUpUserPressed:(id)sender
- {
- //TODO
- //If signup sucessful:
- //[self performSegueWithIdentifier:@"SignupSuccesful" sender:self];
- }
你需要在這里添加注冊操作的代碼,然后檢查是否可以成功注冊。
用以下的代碼替代上面signUpUserPressed方法中的內容:
- //Sign Up Button pressed
- -(IBAction)signUpUserPressed:(id)sender
- {
- //1
- PFUser *user = [PFUser user];
- //2
- user.username = self.userRegisterTextField.text;
- user.password = self.passwordRegisterTextField.text;
- //3
- [user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
- if (!error) {
- //The registration was successful, go to the wall
- [self performSegueWithIdentifier:@"SignupSuccesful" sender:self];
- } else {
- //Something bad has occurred
- NSString *errorString = [[error userInfo] objectForKey:@"error"];
- UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
- [errorAlertView show];
- }
- }];
- }
在以上代碼中,創建一個用戶的步驟是:
注釋1:創建一個新的PFUser對象,這個類是用來登陸和注冊的。它會保儲已經通過驗證的用戶,你可以在你想要的時候訪問這個用戶的數據。你可以在這里找到關 於PFUser的文檔。
注釋2:指定TextFields中的內容為用戶名和密碼。
注釋3:調用在后台注冊用戶的方法,在代碼塊中檢查結果。結果有兩種可能,一種是注冊成功,新用戶被創建,然后視圖轉到照片牆視圖。或者是注冊失敗,產生錯誤信息,你可以對用戶顯示錯誤描述。
編譯運行你的app看是否有錯誤!
為了檢查用戶注冊操作,運行程序,在Log In界面按下Sign Up按鈕,你會看到下圖:
輸入用戶名和密碼,按下Sign Up按鈕,如果順利的話,app會轉到照片牆視圖。
好極了!但你仍需要確認你的新用戶是否已經保存了。打開Data Browser來確認新用戶是否存在,如下圖所示:
恭喜!你第一個用戶已經創建了!現在是時候讓用戶登陸並和后台交互了!
用戶登陸
在這一節,你會學習怎樣讓你在上面創建的用戶進行登陸。
打開LoginviewController.m文件,加上頭文件:
- #import <Parse/Parse.h>
然后看到以下代碼:
- //Login button pressed
- -(IBAction)logInPressed:(id)sender
- {
- //If user logged succesful:
- //[self performSegueWithIdentifier:@"LoginSuccesful" sender:self];
- }
正如你所看到的,這一部分和注冊部分的代碼很相似!你會再次使用PFUser類,但這次你是用它來進行登陸操作的。用以下的代碼替換掉loginPressed方法中的內容:
- //Login button pressed
- -(IBAction)logInPressed:(id)sender
- {
- [PFUser logInWithUsernameInBackground:self.userTextField.text password:self.passwordTextField.text block:^(PFUser *user, NSError *error) {
- if (user) {
- //Open the wall
- [self performSegueWithIdentifier:@"LoginSuccesful" sender:self];
- } else {
- //Something bad has ocurred
- NSString *errorString = [[error userInfo] objectForKey:@"error"];
- UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
- [errorAlertView show];
- }
- }];
- }
代碼和注冊代碼很相似。運行app,你會看到以下界面:
嘗試用你剛才創建的用戶進行登陸,如果順利的話,app應該會轉到照片牆視圖。
照片牆
剛才的操作(注冊和登陸)都會使視圖轉到照片牆視圖,在這個視圖中,你可以看到所用的注冊用戶上傳到后台服務器的帶有評論的照片。
但這在看到照片之前,也得先有照片上傳上去啊!
在Parse上傳文件非常簡單,先看一看UploadImageViewController.m文件,文件就是在這里進行上傳的。
一個已經登陸的用戶可以點擊在照片牆視圖的Upload按鈕,就是導航欄右邊的按鈕,上傳文件的過程就在下面給出。
用戶點擊Upload按鈕時,就會觸發selectPicturePressed方法。系統的照片庫就會出現,讓用戶從中選擇一張圖片,如下所示:
- -(IBAction)selectPicturePressed:(id)sender
- {
- //Open a UIImagePickerController to select the picture
- UIImagePickerController *imgPicker = [[UIImagePickerController alloc] init];
- imgPicker.delegate = self;
- imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
- [self.navigationController presentModalViewController:imgPicker animated:YES];
- }
選好圖片后,圖片就會出現在主界面的UIImageView中,如下所示:
- - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo
- {
- [picker dismissModalViewControllerAnimated:YES];
- //Place the image in the imageview
- self.imgToUpload.image = img;
- }
用戶可以在文本框中輸入對照片的評論,也可以不輸評論,這是可選的。
這些都已經為你做好了!現在應該添加代碼來實現sendPressed方法了。這個方法是導航欄上的按鈕觸發的,用來上傳圖片和評論到服務器。
過程分開兩個部分。首先,用PFFile對象上傳圖片;然后把對象附到PFObject上傳到服務器。
先在UploadImageViewController.m文件開頭加上頭文件:
- #import <Parse/Parse.h>
在-(IBAction)sendPressed:(id)sender方法中加入以下代碼:
- //Upload a new picture
- //1
- PFFile *file = [PFFile fileWithName:@"img" data:pictureData];
- [file saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
- if (succeeded){
- //2
- //Add the image to the object, and add the comment and the user
- PFObject *imageObject = [PFObject objectWithClassName:@"WallImageObject"];
- [imageObject setObject:file forKey:@"image"];
- [imageObject setObject:[PFUser currentUser].username forKey:@"user"];
- [imageObject setObject:self.commentTextField.text forKey:@"comment"];
- //3
- [imageObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
- //4
- if (succeeded){
- //Go back to the wall
- [self.navigationController popViewControllerAnimated:YES];
- }
- else{
- NSString *errorString = [[error userInfo] objectForKey:@"error"];
- UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
- [errorAlertView show];
- }
- }];
- }
- else{
- //5
- NSString *errorString = [[error userInfo] objectForKey:@"error"];
- UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
- [errorAlertView show];
- }
- } progressBlock:^(int percentDone) {
- NSLog(@"Uploaded: %d %%", percentDone);
- }];
下面來解析一下以上代碼:
注釋1:用圖片創建PFFile對象,然后在后台保存它。在代碼塊的末尾你可以檢查上傳的進度。
注釋2:上傳成功后,創建含有圖片和數據的PFObject對象,對象中設置文件,用戶名和評論。
注釋3:在后台中保存PFObject對象。
注釋4:如果成功了,就返回到照片牆視圖。
注釋5:失敗了就通知用戶。
編譯運行你的app!用之前創建的用戶名登陸,來到Upload界面,如下圖所示:
按下Select Picture在相冊中選擇一張圖片,如果想的話,可以寫上評論,在按下Send按鈕。
你可以在控制台中看到上傳的進度。
現在去到Data Browser界面看看,你會看到一個新的名為“WallImageObject”的表和里面的對象,但等等,在app中還沒看到這些圖片對象呢!!
現在是時候獲取這些圖片了!
在照片牆上貼上圖片
WallPicturesViewController.m文件用於展示用戶已上傳的照片。
在WallPictureController.m文件開頭加上頭文件:
- #import <Parse/Parse.h>
getWallImage方法會在視圖加載獲取圖片時調用,現在這個方法還是空的,在這個方法中加入以下代碼:
- -(void)getWallImages
- {
- //Prepare the query to get all the images in descending order
- //1
- PFQuery *query = [PFQuery queryWithClassName:@"WallImageObject"];
- //2
- [query orderByDescending:@"createdAt"];
- [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
- //3
- if (!error) {
- //Everything was correct, put the new objects and load the wall
- self.wallObjectsArray = nil;
- self.wallObjectsArray = [[NSArray alloc] initWithArray:objects];
- [self loadWallViews];
- } else {
- //4
- NSString *errorString = [[error userInfo] objectForKey:@"error"];
- UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
- [errorAlertView show];
- }
- }];
- }
解釋一下:
注釋1:用你想查詢的表的名字創建一個查詢對象。
注釋2:查詢結果根據“createdAt”屬性降序排列。
注釋3:找到符合條件的對象,把WallImageObject類型的對象展示出來。如果順利的話,把下載到的對象替代wallObjectArray數組中的內容。
注釋4:出錯了的話就告知用戶。
對象下載好后,就要在照片牆上展示它了!看到loadWallImage方法,加入以下代碼:
- -(void)loadWallViews
- {
- //Clean the scroll view
- for (id viewToRemove in [self.wallScroll subviews]){
- if ([viewToRemove isMemberOfClass:[UIView class]])
- [viewToRemove removeFromSuperview];
- }
- //For every wall element, put a view in the scroll
- int originY = 10;
- for (PFObject *wallObject in self.wallObjectsArray){
- //1
- //Build the view with the image and the comments
- UIView *wallImageView = [[UIView alloc] initWithFrame:CGRectMake(10, originY, self.view.frame.size.width - 20 , 300)];
- //2
- //Add the image
- PFFile *image = (PFFile *)[wallObject objectForKey:@"image"];
- UIImageView *userImage = [[UIImageView alloc] initWithImage:[UIImage imageWithData:image.getData]];
- userImage.frame = CGRectMake(0, 0, wallImageView.frame.size.width, 200);
- [wallImageView addSubview:userImage];
- //3
- //Add the info label (User and creation date)
- NSDate *creationDate = wallObject.createdAt;
- NSDateFormatter *df = [[NSDateFormatter alloc] init];
- [df setDateFormat:@"HH:mm dd/MM yyyy"];
- //4
- UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 210, wallImageView.frame.size.width,15)];
- infoLabel.text = [NSString stringWithFormat:@"Uploaded by: %@, %@", [wallObject objectForKey:@"user"], [df stringFromDate:creationDate]];
- infoLabel.font = [UIFont fontWithName:@"Arial-ItalicMT" size:9];
- infoLabel.textColor = [UIColor whiteColor];
- infoLabel.backgroundColor = [UIColor clearColor];
- [wallImageView addSubview:infoLabel];
- //5
- //Add the comment
- UILabel *commentLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 240, wallImageView.frame.size.width, 15)];
- commentLabel.text = [wallObject objectForKey:@"comment"];
- commentLabel.font = [UIFont fontWithName:@"ArialMT" size:13];
- commentLabel.textColor = [UIColor whiteColor];
- commentLabel.backgroundColor = [UIColor clearColor];
- [wallImageView addSubview:commentLabel];
- //6
- [self.wallScroll addSubview:wallImageView];
- originY = originY + wallImageView.frame.size.width + 20;
- }
- //7
- //Set the bounds of the scroll
- self.wallScroll.contentSize = CGSizeMake(self.wallScroll.frame.size.width, originY);
- }
第一步就是清理scrollView中的東西,然后你遍歷了數組中的內容。每個數組元素就是一個PFObject對象,對象包含了一個PFFile。
對於數組中的每個對象:
注釋1:創建包含圖片和評論的視圖。
注釋2:取得圖片對象數據(從PFFile中),然后用數據初始化一個UIImageView對象。
注釋3:取得對象的創建信息。
注釋4:取得上傳圖片的用戶名,把它和創建數據放到一個label中。
注釋5:將評論放到另一個label中。
注釋6:將內容添加到scrollView中。
當每個對象都被解析過后,就根據最后的視圖的大小和位置來設置scrollview的邊界。
編譯運行app!不出意外的話,你就會看到你之前上傳的圖片和評論了。花點時間上傳更多的圖片和評論,看看它們在照片牆上展示出來的效果吧。
感覺很好吧?
退出登陸
這篇教程的最后一部分就是怎么讓用戶退出登陸。為此,看到WallPictureViewController.m文件中的logoutPressed方法,在這個方法中加入以下代碼:
- -(IBAction)logoutPressed:(id)sender
- {
- [PFUser logOut];
- [self.navigationController popViewControllerAnimated:YES];
- }
運行項目,這就搞定了!
教程來到這里也差不多結束了,希望這篇教程能給需要的人帶來一點幫助。PS:翻譯真的很累。。向那些默默為我們翻譯各種外國好文章的大神們致敬!