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 //網絡請求用的API 2 NSString *urlString = @"https://api.weibo.com/2/common/get_country.json?access_token=你自己的access_token"; 3 4 //把urlString轉換成url 5 NSURL *url = [NSURL URLWithString:urlString]; 6 7 //創建URL請求 8 NSURLRequest *request = [NSURLRequest requestWithURL:url]; 9 10 //copy_self在Block中使用,避免強引用循環 11 __weak __block ChinaTableViewController *copy_self = self; 12 13 //執行請求 14 [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 15 16 //連接失敗時 17 if (connectionError) { 18 NSLog(@"%@", [connectionError localizedDescription]); 19 return ; 20 } 21 22 23 NSError *error = nil; 24 //把json轉換成數組 25 copy_self.dataSource = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error]; 26 27 //轉換失敗 28 if (error) { 29 NSLog(@"%@", [error localizedDescription]); 30 return; 31 } 32 33 //tableView的重載 34 [copy_self.tableView reloadData]; 35 36 }];
代碼說明:
1.創建要請求的API,根據你要獲取的數據參考API來拼接你要的URL.
2.根據拼接的URL來創建URL請求對象;
3.發送請求,上面用的是異步請求方式,同步請求會阻塞線程。
4.在block回調中把返回的JSON解析成數組並加載到我們的表示圖
(4).把數據顯示在表視圖上
1 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 2 { 3 return 1; 4 } 5 6 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 7 { 8 return self.dataSource.count; 9 } 10 11 12 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 13 { 14 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; 15 16 NSString *key = [NSString stringWithFormat:@"%03d",indexPath.row+1]; 17 cell.textLabel.text = self.dataSource[indexPath.row][key]; 18 19 20 return cell; 21 }
(5)因為在下一個頁面要請求數據的時候得用到第一個頁面的數據,也就是在請求省份的時候得知道國家的編碼,所以要把國家的編碼傳到第二個頁面中,第三個頁面和第二個頁面也是類似。下面是通過KVC傳值的代碼
1 // In a storyboard-based application, you will often want to do a little preparation before navigation 2 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 3 { 4 5 UITableViewCell *cell = sender; 6 7 //獲取點擊Cell的索引 8 NSIndexPath * indexPath = [self.tableView indexPathForCell:cell]; 9 10 //獲取請求的數據 11 NSDictionary *dic = self.dataSource[indexPath.row]; 12 13 id vc = [segue destinationViewController]; 14 [vc setValue:dic forKey:@"country"]; 15 16 }
后兩個顯示頁面和上面的代碼相似,在這就不做贅述,Get數據的關鍵是讀懂API,通過API獲取你想要的數據
2.POST請求方式
我們下面通過調用新浪微博發微博的API來了解一下通過POST提交表單中的數據,在用第三方的類庫AFNetWorking來提交圖片,至於發微博的API如何使用請參照新浪官方的API開發文檔。
(1)通過POST提交純表單數據
a.用POST方式提交,不需要往URL中拼接參數,首先我們要獲取url(API中提供的發布微博的URL,下面用的宏定義的URL)
//獲取url NSURL *url = [NSURL URLWithString:SendMessage];
b.通過URL創建一個可變的請求:
//創建POST請求 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
c.把請求方式設置成POST
//設置POST請求 [request setHTTPMethod:@"POST"];
d.拼接要提交的參數
//拼接要POST提交的字符串 NSString *string = [NSString stringWithFormat:@"access_token=%@&status=%@", access_token, self.blogTextField.text];
e.在網絡傳輸中我們使用的時二進制所以要轉換成NSData類型
//把string轉變成NSData類型 NSData *bodyData = [string dataUsingEncoding:NSUTF8StringEncoding];
f.把參數添加到請求中
//把bodyData添加到request中 request.HTTPBody = bodyData;
g.發送請求
//執行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來組織我們的數據,數據是存儲在字典中的
NSDictionary *dic = @{@"access_token": access_token, @"status":self.blogTextField.text};
b.獲取請求操作,並傳入字典,POST后面跟的時API中提供的URL。 self.manager是我們之前定義的屬性@property (strong, nonatomic) AFHTTPRequestOperationManager * manager; 並在viewDidLoad中分配內存
AFHTTPRequestOperation *op = [self.manager POST:SendImage parameters:dic constructingBodyWithBlock:^(id<AFMultipartFormData> 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.得啟動才可提交
//配置解析過程 op.responseSerializer = [AFCompoundResponseSerializer serializer]; //啟動請求 [op start];
效果如下:
3.如果我們的圍脖到這那不太簡單了蠻,如果到這就結束的話,下面又該有小伙伴評論“這有什么意義呢?”,下面就請求一下我的圍脖的內容,點進去是本條圍脖的評論,效果圖如下:
上面的內容是用新浪微博提供的API用我自己的token請求的內容,和我登陸圍脖賬號的首頁是一樣的數據,點進去是該微博的所有評論,當然啦,上面為了省事,我們用Cell是在Storyboard中設置的。真正實現起來需要新建TableViewCell根據數據來定制我們想要的cell, 之后在TableViewController中進行注冊一下就可以用了。獲取微博內容的代碼和上面國家的代碼類似,在這就不往上貼代碼了。我們往cell中添加網絡請求的圖片時用的時AFNetWorking中的UIKit+AFNetworking.h類目,大大簡化了我們網絡請求圖片的操作。設置圖片的代碼如下:
1 NSURL *url = [NSURL URLWithString:dic[@"user"][@"profile_image_url"]]; 2 [cell.imageView setImageWithURL:url];
如果你感覺到這這篇博文就結束啦?不可能的啦!!上面的博文都顯示不出來,還有發布時間,圖片等最基本的信息都沒有。在之前的博客中有一篇“IOS開發之自動布局顯示網絡請求內容” ,用的網絡請求是模擬的微博請求,博文的內容也是模擬的,接下來要用到上一篇博文的知識:根據請求內容來動態的設置Cell的高度。下面就讓我們自定義兩種Cell來把上面的TableView完善一下吧:
1.創建兩種Cell,並給Cell中的各個控件設置約束
2.上面的cell是我們自定義的cell,需要關聯兩個UITableViewCell類,然后在Cell對象中進行控件的配置和賦值,其中的一個自定義Cell的關鍵代碼如下,在TableView中我們只需要調用setCellContent方法把存有數據的字典傳到cell中中由cell賦值即可:
1 @interface TextTableViewCell() 2 3 @property (strong, nonatomic) IBOutlet UIImageView *image; 4 5 6 @property (strong, nonatomic) IBOutlet UILabel *titleLable; 7 @property (strong, nonatomic) IBOutlet UILabel *dateLabel; 8 @property (strong, nonatomic) IBOutlet UILabel *contentLable; 9 10 @end 11 12 @implementation TextTableViewCell 13 14 -(void)setCellContent:(NSDictionary *)dic 15 { 16 17 NSDateFormatter *iosDateFormater=[[NSDateFormatter alloc]init]; 18 iosDateFormater.dateFormat=@"EEE MMM d HH:mm:ss Z yyyy"; 19 //必須設置,否則無法解析 20 iosDateFormater.locale=[[NSLocale alloc]initWithLocaleIdentifier:@"en_US"]; 21 NSDate *date=[iosDateFormater dateFromString:dic[@"created_at"]]; 22 23 //目的格式 24 NSDateFormatter *resultFormatter=[[NSDateFormatter alloc]init]; 25 [resultFormatter setDateFormat:@"MM月dd日 HH:mm"]; 26 27 self.dateLabel.text = [resultFormatter stringFromDate:date]; 28 29 self.titleLable.text = dic[@"user"][@"name"]; 30 31 self.contentLable.text = dic[@"text"]; 32 33 NSURL *imgURL = [NSURL URLWithString:dic[@"user"][@"profile_image_url"]]; 34 [self.image setImageWithURL:imgURL]; 35 36 }
3、我們需要在原來顯示微博的TableView中根據請求的數據來選擇用哪一個Cell,選擇代碼如下:
1 //選擇判斷用哪個cell 2 -(UITableViewCell *)selectCell:(NSDictionary *)dic cellForRowAtIndexPath:(NSIndexPath *)indexPath 3 { 4 UITableViewCell *cell = nil; 5 6 //根據下面是否有圖片來判斷選擇哪一個Cell 7 if (dic[@"thumbnail_pic" ] == nil) 8 { 9 cell = [self.tableView dequeueReusableCellWithIdentifier:@"textCell" forIndexPath:indexPath]; 10 } 11 else 12 { 13 cell = [self.tableView dequeueReusableCellWithIdentifier:@"imageCell" forIndexPath:indexPath]; 14 } 15 16 return cell; 17 }
4.根據微博內容來動態的調整cell的高度:
//根據博文的內容調整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 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 2 { 3 NSDictionary *dic = self.array[indexPath.row]; 4 5 UITableViewCell *cell = [self selectCell:dic cellForRowAtIndexPath:indexPath]; 6 7 //把值給我們的cell,讓cell設置其自己的屬性 8 [cell setCellContent:dic]; 9 10 return cell; 11 }
上面的時核心代碼,加入后我們在來看一下我們請求的效果吧,是不是看着像那么一回事兒啦,今天的博客的內容先到這吧,以后會繼續完善我們的圍脖的:
如果有小伙伴感覺上面太簡單的化,可以來的復雜的,如果微博是轉發的把轉發的微博顯示出來,下面我們把轉發的帶圖片的和不帶圖片的博文顯示出來,並在下面加上轉發,評論和贊的按鈕。
需求難點:
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塊類型的代碼:
//創建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 -(void)setTagButtonBlock:(CellBlock)cellBlock 2 { 3 self.block = cellBlock; 4 }
d.點擊不同的button是給傳入的block設置不同的值,也就是把Button的tag傳入到block中。添加的三個按鈕對應着一個回調方法,代碼如下:
1 - (IBAction)tapComment:(id)sender { 2 UIButton *button = sender; 3 4 self.block(self, button.tag); 5 }
(3)在我們的TableView中實現Cell的回調,給據回調參數Button.tag的值的不同,去執行相應的業務邏輯,回調的代碼如下:
- (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; }
經過上面的那些代碼的修飾,我們的新浪微博的效果如下,因為令牌是用我自己的微博賬號申請的,所以顯示的東西和我新浪微博的主頁是一樣的: