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;
}
經過上面的那些代碼的修飾,我們的新浪微網誌的效果如下,因為令牌是用我自己的微網誌賬号申請的,是以顯示的東西和我新浪微網誌的首頁是一樣的:
作者:青玉伏案
出處:http://www.cnblogs.com/ludashi/
本文版權歸作者和共部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。
如果文中有什麼錯誤,歡迎指出。以免更多的人被誤導。
收履歷:某網際網路公司,招聘iOS/Android靠譜工程師,入職後,可内部聯系樓主,有小禮品贈送,有意者可郵箱投遞履歷:[email protected]