IOS開發和Web開發一樣,網路請求方式包括Get和Post方式。Get和Post兩者有和特點和區別,在本篇部落格中不做過多的論述,本篇的重點在於如何GET資料和POST資料。下面還會提到如何在我們的專案中使用CocoaPods, CocoaPods的安裝和使用教程請參考連結http://code4app.com/article/cocoapods-install-usage。上面詳細的介紹了CocoaPods的安裝過程和如何通過CocoaPods引入第三方類庫。在本篇部落格中提到CocoaPods,是因為我們需要用CocoaPods來引入AFNetWorking,然後在網路請求中使用AFNetWorking來實現我們圖片的提交。
下面用的API是由新浪微博提供的官方API,連結地址:http://open.weibo.com/wiki/微博API, 想使用新浪微博的API首先得註冊成開發者獲取一個和自己新浪微博繫結的access_token,我們可以通過這個令牌來使用新浪微博提供的API.
1.Get方式的請求
(1)下面會使用公共服務的國家,省份,和城市的介面,來學習一下GET請求方式
(2)我們要完成什麼要的任務呢?少說點吧,上幾張圖最為直接
(3)上面的資料是通過API獲取的,獲取完後再顯示在我們的tableView中,將會提供一些關鍵的實現程式碼,準備工作是新建三個TabelViewController然後配置相應的cell。下面就以第一個TableView為例,因為後兩個和第一個差不多,所以就不做贅述,下面是網路請求的關鍵程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
//網路請求用的API NSString *urlString = @"https://api.weibo.com/2/common/get_country.json?access_token=你自己的access_token"; //把urlString轉換成url NSURL *url = [NSURL URLWithString:urlString]; //建立URL請求 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //copy_self在Block中使用,避免強引用迴圈 __weak __block ChinaTableViewController *copy_self = self; //執行請求 [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { //連線失敗時 if (connectionError) { NSLog(@"%@", [connectionError localizedDescription]); return ; } NSError *error = nil; //把json轉換成陣列 copy_self.dataSource = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error]; //轉換失敗 if (error) { 29 NSLog(@"%@", [error localizedDescription]); return; } //tableView的過載 [copy_self.tableView reloadData]; }]; |
程式碼說明:
1.建立要請求的API,根據你要獲取的資料參考API來拼接你要的URL.
2.根據拼接的URL來建立URL請求物件;
3.傳送請求,上面用的是非同步請求方式,同步請求會阻塞執行緒。
4.在block回撥中把返回的JSON解析成陣列並載入到我們的表示圖
(4).把資料顯示在表檢視上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataSource.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; NSString *key = [NSString stringWithFormat:@"%03d",indexPath.row+1]; cell.textLabel.text = self.dataSource[indexPath.row][key]; return cell; } |
(5)因為在下一個頁面要請求資料的時候得用到第一個頁面的資料,也就是在請求省份的時候得知道國家的編碼,所以要把國家的編碼傳到第二個頁面中,第三個頁面和第二個頁面也是類似。下面是通過KVC傳值的程式碼
1 2 3 4 5 6 7 8 9 10 11 12 |
// In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { UITableViewCell *cell = sender; //獲取點選Cell的索引 NSIndexPath * indexPath = [self.tableView indexPathForCell:cell]; //獲取請求的資料 NSDictionary *dic = self.dataSource[indexPath.row]; id vc = [segue destinationViewController]; [vc setValue:dic forKey:@"country"]; } |
後兩個顯示頁面和上面的程式碼相似,在這就不做贅述,Get資料的關鍵是讀懂API,通過API獲取你想要的資料
2.POST請求方式
我們下面通過呼叫新浪微博發微博的API來了解一下通過POST提交表單中的資料,在用第三方的類庫AFNetWorking來提交圖片,至於發微博的API如何使用請參照新浪官方的API開發文件。
(1)通過POST提交純表單資料
a.用POST方式提交,不需要往URL中拼接引數,首先我們要獲取url(API中提供的釋出微博的URL,下面用的巨集定義的URL)
1 2 |
//獲取url NSURL *url = [NSURL URLWithString:SendMessage]; |
b.通過URL建立一個可變的請求:
1 2 |
//建立POST請求 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; |
c.把請求方式設定成POST
1 2 |
//設定POST請求 [request setHTTPMethod:@"POST"]; |
d.拼接要提交的引數
1 2 |
//拼接要POST提交的字串 NSString *string = [NSString stringWithFormat:@"access_token=%@&status=%@", access_token, self.blogTextField.text]; |
e.在網路傳輸中我們使用的時二進位制所以要轉換成NSData型別
1 2 |
//把string轉變成NSData型別 NSData *bodyData = [string dataUsingEncoding:NSUTF8StringEncoding]; |
f.把引數新增到請求中
1 2 |
//把bodyData新增到request中 request.HTTPBody = bodyData; |
g.傳送請求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//執行request [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { NSError *error; NSDictionary *dic =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error]; if (error) { NSLog(@"%@", [error localizedDescription]); } NSLog(@"%@", dic); }]; |
到此微博傳送成功,會在我們自己的新浪微博的主頁中顯示我們在模擬器中的文字輸入的東西了,因為我新增的應用的access_token沒有申請稽核,所以會顯示“來自未通過稽核應用”,截圖如下:
2.我們如何通過呼叫可以發圖片的API上傳本地圖片呢?為了簡化我們APP的圖片的上傳,我們就得用到AFNetWorking中的東西了,如何配置和使用CocoaPods請參考上面的連結。
a.用AFHTTPRequestOperationManager來組織我們的資料,資料是儲存在字典中的
1 |
NSDictionary *dic = @{@"access_token": access_token, @"status":self.blogTextField.text}; |
b.獲取請求操作,並傳入字典,POST後面跟的時API中提供的URL。 self.manager是我們之前定義的屬性@property (strong, nonatomic) AFHTTPRequestOperationManager * manager; 並在viewDidLoad中分配記憶體
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
AFHTTPRequestOperation *op = [self.manager POST:SendImage parameters:dic constructingBodyWithBlock:^(id formData) { //把圖片轉換成NSData型別的資料 NSData *imageData = UIImagePNGRepresentation(self.buttonImage.imageView.image);//把圖片拼接到資料中 [formData appendPartWithFileData:imageData name:@"pic" fileName:@"123" mimeType:@"image/png"]; } success:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"%@", responseObject); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"%@",[error localizedDescription]); }]; |
c.得啟動才可提交
1 2 3 4 5 6 7 |
//配置解析過程 op.responseSerializer = [AFCompoundResponseSerializer serializer]; //啟動請求 [op start]; |
效果如下:
3.如果我們的圍脖到這那不太簡單了蠻,如果到這就結束的話,下面又該有小夥伴評論“這有什麼意義呢?”,下面就請求一下我的圍脖的內容,點進去是本條圍脖的評論,效果圖如下:
上面的內容是用新浪微博提供的API用我自己的token請求的內容,和我登陸圍脖賬號的首頁是一樣的資料,點進去是該微博的所有評論,當然啦,上面為了省事,我們用Cell是在Storyboard中設定的。真正實現起來需要新建TableViewCell根據資料來定製我們想要的cell, 之後在TableViewController中進行註冊一下就可以用了。獲取微博內容的程式碼和上面國家的程式碼類似,在這就不往上貼程式碼了。我們往cell中新增網路請求的圖片時用的時AFNetWorking中的UIKit+AFNetworking.h類目,大大簡化了我們網路請求圖片的操作。設定圖片的程式碼如下:
1 2 |
NSURL *url = [NSURL URLWithString:dic[@"user"][@"profile_image_url"]]; [cell.imageView setImageWithURL:url]; |
如果你感覺到這這篇博文就結束啦?不可能的啦!!上面的博文都顯示不出來,還有釋出時間,圖片等最基本的資訊都沒有。在之前的部落格中有一篇“IOS開發之自動佈局顯示網路請求內容” ,用的網路請求是模擬的微博請求,博文的內容也是模擬的,接下來要用到上一篇博文的知識:根據請求內容來動態的設定Cell的高度。下面就讓我們自定義兩種Cell來把上面的TableView完善一下吧:
1.建立兩種Cell,並給Cell中的各個控制元件設定約束
2.上面的cell是我們自定義的cell,需要關聯兩個UITableViewCell類,然後在Cell物件中進行控制元件的配置和賦值,其中的一個自定義Cell的關鍵程式碼如下,在TableView中我們只需要呼叫setCellContent方法把存有資料的字典傳到cell中中由cell賦值即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@interface TextTableViewCell() @property (strong, nonatomic) IBOutlet UIImageView *image; @property (strong, nonatomic) IBOutlet UILabel *titleLable; @property (strong, nonatomic) IBOutlet UILabel *dateLabel; @property (strong, nonatomic) IBOutlet UILabel *contentLable; @end @implementation TextTableViewCell -(void)setCellContent:(NSDictionary *)dic { NSDateFormatter *iosDateFormater=[[NSDateFormatter alloc]init]; iosDateFormater.dateFormat=@"EEE MMM d HH:mm:ss Z yyyy"; //必須設定,否則無法解析 iosDateFormater.locale=[[NSLocale alloc]initWithLocaleIdentifier:@"en_US"]; NSDate *date=[iosDateFormater dateFromString:dic[@"created_at"]]; //目的格式 NSDateFormatter *resultFormatter=[[NSDateFormatter alloc]init]; [resultFormatter setDateFormat:@"MM月dd日 HH:mm"]; self.dateLabel.text = [resultFormatter stringFromDate:date]; self.titleLable.text = dic[@"user"][@"name"]; self.contentLable.text = dic[@"text"]; NSURL *imgURL = [NSURL URLWithString:dic[@"user"][@"profile_image_url"]]; [self.image setImageWithURL:imgURL]; } |
3、我們需要在原來顯示微博的TableView中根據請求的資料來選擇用哪一個Cell,選擇程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//選擇判斷用哪個cell -(UITableViewCell *)selectCell:(NSDictionary *)dic cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = nil; //根據下面是否有圖片來判斷選擇哪一個Cell if (dic[@"thumbnail_pic" ] == nil) { cell = [self.tableView dequeueReusableCellWithIdentifier:@"textCell" forIndexPath:indexPath]; } else { cell = [self.tableView dequeueReusableCellWithIdentifier:@"imageCell" forIndexPath:indexPath]; } return cell; } |
4.根據微博內容來動態的調整cell的高度:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//根據博文的內容調整cell的高度 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { NSDictionary *dic = self.array[indexPath.row]; NSString *text = dic[@"text"]; //用字典設定字型的大小 NSDictionary * dic1 = @{NSFontAttributeName: [UIFont systemFontOfSize:14]}; CGRect frame = [text boundingRectWithSize:CGSizeMake(276, 1000) options:NSStringDrawingUsesLineFragmentOrigin attributes:dic1 context:nil]; CGFloat height = frame.size.height; //不同型別的cell高度不同 if (dic[@"thumbnail_pic" ] == nil) { height = height + 59 + 25; } else { height = height + 59 + 25+ 105; } return height; } |
5.上面是新增的程式碼,下面我們需要把獲取cell的方法進行修改,如下:
1 2 3 4 5 6 7 8 |
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSDictionary *dic = self.array[indexPath.row]; UITableViewCell *cell = [self selectCell:dic cellForRowAtIndexPath:indexPath]; //把值給我們的cell,讓cell設定其自己的屬性 [cell setCellContent:dic]; return cell; } |
上面的時核心程式碼,加入後我們在來看一下我們請求的效果吧,是不是看著像那麼一回事兒啦,今天的部落格的內容先到這吧,以後會繼續完善我們的圍脖的:
如果有小夥伴感覺上面太簡單的化,可以來的複雜的,如果微博是轉發的把轉發的微博顯示出來,下面我們把轉發的帶圖片的和不帶圖片的博文顯示出來,並在下面加上轉發,評論和讚的按鈕。
需求難點:
1.cell的高度根據本博文和轉發博文的多少而改變,就是在cell中有兩部分內容的高度是變化的,需要用程式碼來動態控制其高度。先給自己發的博文設定一個垂直約束,下面轉發的博文只設定編輯約束,不設定高度約束。我們根據博文文字的多少來用程式碼動態的改變垂直約束,至於如何用程式碼改變約束的值,請參照以前的部落格IOS開發之絕對佈局和相對佈局(螢幕適配),在這就不做過多的論述,下面主要講如何給我們的cell新增多個按鈕,然後在點選按鈕的時候我們知道是那個Cell的那個button被點選了。
(1)為了區分按鈕,我們需要給每個按鈕設定tag,然後在TableViewController中獲取Tag的值,我們就知道是那個按鈕被點選了。
(2)難點在於我們如何判斷被點選的按鈕位於那個cell上。這個得用block回撥來解決問題啦。
a.在我們Cell的類中需要定義一個block塊的型別變數,用於在TableViewController中回撥使用,在block回撥時,我們就可以把那個Cell以及Cell中被點選的按鈕傳到TableViewController中啦,至於想深入的瞭解一下block回撥,請參考前面的部落格Objective-C中的Block回撥模式。下面是在Cell對應的類中,宣告Block塊型別的程式碼:
1 2 |
//建立cell的block塊把按鈕的tag傳到ViewController中 typedef void (^CellBlock) (ReTextTableViewCell * cell, int buttonTag); |
b.在Cell中新增CellBlock型別的變數,用於接收回撥
1 |
@property (strong, nonatomic) CellBlock block; |
c.新增設定block的setter方法,引數是要傳入的block塊
1 2 3 4 |
-(void)setTagButtonBlock:(CellBlock)cellBlock { self.block = cellBlock; } |
d.點選不同的button是給傳入的block設定不同的值,也就是把Button的tag傳入到block中。新增的三個按鈕對應著一個回撥方法,程式碼如下:
1 2 3 4 5 |
- (IBAction)tapComment:(id)sender { UIButton *button = sender; self.block(self, button.tag); } |
(3)在我們的TableView中實現Cell的回撥,給據回撥引數Button.tag的值的不同,去執行相應的業務邏輯,回撥的程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSDictionary *dic = self.array[indexPath.row]; UITableViewCell *cell = [self selectCell:dic cellForRowAtIndexPath:indexPath]; //把值給我們的cell,讓cell設定其自己的屬性 [cell setCellContent:dic]; __weak __block NSDictionary *copy_dic = dic; __weak __block SinaBlogTableViewController *copy_self = self; if ([cell isKindOfClass:[ReTextTableViewCell class]] || [cell isKindOfClass:[ReImageTableViewCell class]]) { ReTextTableViewCell * cellTemp =( ReTextTableViewCell *) cell; [cellTemp setTagButtonBlock:^(ReTextTableViewCell *cell, int buttonTag) { switch (buttonTag) { case 1: { NSLog(@"轉發"); NSString *str = @"https://api.weibo.com/2/statuses/repost.json"; NSDictionary *dic = @{@"access_token":@"你自己的令牌" ,@"id":[NSString stringWithFormat:@"%@",copy_dic[@"id"]]}; //用AFHTTPRequestOperationManager來組織我們的資料,資料是儲存在字典中的 AFHTTPRequestOperation *op = [self.manager POST:str parameters:dic success:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"%@",responseObject); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"%@",[error localizedDescription]); }]; //配置解析過程 op.responseSerializer = [AFJSONResponseSerializer serializer]; //啟動請求 [op start]; } break; case 2: { NSLog(@"評論"); UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]]; id vc = [storyboard instantiateViewControllerWithIdentifier:@"Comments"]; [vc setValue:copy_dic forKey:@"userInfo"]; [copy_self.navigationController pushViewController:vc animated:YES]; } break; case 3: NSLog(@"贊"); break; default: break; } }]; } return cell; } |
經過上面的那些程式碼的修飾,我們的新浪微博的效果如下,因為令牌是用我自己的微博賬號申請的,所以顯示的東西和我新浪微博的主頁是一樣的:
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!