IOS開發和Web開發同樣,網絡請求方式包括Get和Post方式。Get和Post二者有和特色和區別,在本篇博客中不作過多的論述,本篇的重點在於如何GET數據和POST數據。下面還會提到如何在咱們的項目中使用CocoaPods, CocoaPods的安裝和使用教程請參考連接http://code4app.com/article/cocoapods-install-usage。上面詳細的介紹了CocoaPods的安裝過程和如何經過CocoaPods引入第三方類庫。在本篇博客中提到CocoaPods,是由於咱們須要用CocoaPods來引入AFNetWorking,而後在網絡請求中使用AFNetWorking來實現咱們圖片的提交。
html
下面用的API是由新浪微博提供的官方API,連接地址:http://open.weibo.com/wiki/微博API, 想使用新浪微博的API首先得註冊成開發者獲取一個和本身新浪微博綁定的access_token,咱們能夠經過這個令牌來使用新浪微博提供的API.ios
1.Get方式的請求json
(1)下面會使用公共服務的國家,省份,和城市的接口,來學習一下GET請求方式api
(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 }];
代碼說明:app
1.建立要請求的API,根據你要獲取的數據參考API來拼接你要的URL.異步
2.根據拼接的URL來建立URL請求對象;佈局
3.發送請求,上面用的是異步請求方式,同步請求會阻塞線程。post
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 }
三、咱們須要在原來顯示微博的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; }
通過上面的那些代碼的修飾,咱們的新浪微博的效果以下,由於令牌是用我本身的微博帳號申請的,因此顯示的東西和我新浪微博的主頁是同樣的: