天天看點

OC學習日記17 (三) get和postget和post

get和post

前言

get和post是我們實作API接口功能所需要的兩種方式,實際上需要哪種根據網站對此的要求,而我們擷取到所要的消息前,根據程序繼續執行與否,我們又分為同步和異步兩種方式。是以,我們實際上一共要學習同步get、同步post、異步get、異步post四種方式。

API接口

例子:

我們首先要為自己的軟體找一個合适的API接口,這裡我就以新浪接口為例子:

注冊成功後,我們随便先注冊一個企業級測試應用,然後我們就有了對應的access_token值,這個值是所有新浪微網誌的API接口都必要的一個值。

(圖檔之後補上)

然後我們點選文檔-API文檔,找到我們需要實作的功能對應的API接口,如果我們有不懂的可以找到API測試工具去把我們要的接口選中,它會給出傳回的資料的形式和例子

(圖檔之後補上)

我們以其中公共微網誌為例,我們可以找到擷取公共微網誌的API接口為statuses/public_timeline:

對于get方式而言:

我們需要接口的最終URL位址為:

接口的json的URL位址+?+我們這個接口需要的參數&參數….

(必要的寫上,可選的根據需要寫,參數之間用&符号連接配接)

https://api.weibo.com/2/statuses/public_timeline.json + ? +access_token=|這裡寫我們擷取到的API接口的access_token|+?+|需要的其他可選參數|

這裡我們舉例子是以隻需要用到必要的access_token參數,代碼如下:

NSString *urlString = @"https://api.weibo.com/2/statuses/public_timeline.json?access_token=|這裡寫我們擷取到的API接口的access_token|";
           

同步get

擷取正确的伺服器URL位址

我們首先要把需要的API接口檔案的最終URL用字元串接收,如果此URL含有特殊字元或中文,我們就要對此進行編碼(最好進行此步驟),編碼後将其轉為NSURL類型。

- (IBAction)synchronizationGet:(UIButton *)sender {
    NSLog(@"同步get");
    NSString *urlString = @"https://api.weibo.com/2/statuses/public_timeline.json?access_token=|這裡寫我們擷取到的API接口的access_token|";
    //編碼
    urlString =[urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSURL *url=[NSURL URLWithString:urlString];
           

伺服器連接配接

然後我們用NSURLConnection類型提供的方法,如果同步就用sendSynchronousRequest方法,異步就用sendAsynchronousRequest方法與伺服器進行連接配接。然後我們根據此方法需要的參數,去建立NSURLRequest、NSURLResponse、NSError三種類型的資料。我們除此之外還可以用NSURLConnectionDataDelegate協定代理的方法去進行伺服器連接配接。

//建立一個url請求
    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:];
    NSURLResponse *httpURLResponse;
    NSError *error;
    //NSURLConnection類,和伺服器連接配接
    NSData *data=[NSURLConnection sendSynchronousRequest:request returningResponse:&httpURLResponse error:&error];
           

JSON資料格式解析

直接解析

//JSON資料格式解析,利用系統提供的API進行JSON資料解析
NSDictionary *dictionary=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
NSLog(@"dictionary = %@",dictionary);
NSDictionary *dic=[dictionary[@"statuses"] objectAtIndex: ];
NSString *text=dic[@"text"];
}
           

用相應類解析

或者,我們可以用一個類去解析我們得到的JSON資料,這樣子我們可以拆掉我們不要的外層資料,在大資料中,這樣可以減輕我們解析的負擔
           
//JSON資料格式解析,利用系統提供的API進行JSON資料解析
    NSDictionary *dictionary=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
    WeiboMode *mode1=[[WeiboMode alloc ]initWithDictionary:dictionary];
    NSString *text=[mode1.statuses[] objectForKey:@"text"];
    NSLog(@"%@",text);
    self.textView.text=text;
}
           

建一個解析json資料的類

由于我們擷取到新浪微網誌傳回的資料比較繁雜,而且我們每次得到的資料裡面的外層結構都是一樣的,我們可以建一個相關的類去解析資料
           

.h檔案裡面:

在聲明檔案中,我們首先如果要解析每一層資料,就要把此層的資料全部作為屬性列出來,不然會報錯。
           
#import <Foundation/Foundation.h>

@interface WeiboMode : NSObject
@property (nonatomic,strong)NSArray *statuses;
@property (nonatomic,strong)NSNumber *hasvisible;
@property (nonatomic,strong)NSNumber *previous_cursor;
@property (nonatomic,strong)NSNumber *next_cursor;
@property (nonatomic,strong)NSNumber *total_number;
@property (nonatomic,strong)NSNumber *interval;
-(id)initWithDictionary:(NSDictionary *)dictionary;
@end
           

.m檔案:

#import "WeiboMode.h"
@implementation WeiboMode
-(id)initWithDictionary:(NSDictionary *)dictionary{
    if (self=[super init]) {
        [self setValuesForKeysWithDictionary:dictionary];
    }
    return self;
}
@end
           

異步get

擷取正确的伺服器URL位址

- (IBAction)AynchronizationGet:(UIButton *)sender {
    NSString *urlString = @"https://api.weibo.com/2/statuses/public_timeline.json?access_token=|這裡寫我們擷取到的API接口的access_token|";
    //編碼
    urlString =[urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSURL *url=[NSURL URLWithString:urlString];
    //建立一個url請求
    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:];
           

伺服器連接配接

伺服器連接配接有兩種方法,我們可以用協定代理的方法或直接請求的方法
           

用代理的方法伺服器連接配接

(如果将異步的get和post兩個方法寫到同一個代理中,我們将此定義為全局變量,後面會提到)

NSURLConnection &connectionGet= [NSURLConnection connectionWithRequest:request delegate:self];
           

實作NSURLConnectionDataDelegate協定代理的必要的一些方法(接受完資料後,在connectionDidFinishLoading方法中解析JSON資料)

(為了接受資料,定義一個全局變量_mDataGet)

@interface ViewController ()<NSURLConnectionDataDelegate>
{
    NSMutableData *_mDataGet;
}
@end
           
伺服器開始響應,準備向客戶發送資料
-(void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response{
    NSLog(@"伺服器開始響應,準備向客戶發送資料");
        _mDataGet=[NSMutableData data];


           
從伺服器接收到資料,并且此方法會執行多次
-(void)connection:(NSURLConnection *)connection
   didReceiveData:(NSData *)data{
    NSLog(@"從伺服器接收到資料,并且此方法會執行多次");
        [_mDataGet appendData:data];
}
           
伺服器接收資料完成
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{ 
        NSLog(@"伺服器接收資料完成");  
        NSDictionary *dictionary=[NSJSONSerialization JSONObjectWithData:_mDataGet options:NSJSONReadingAllowFragments error:nil];
        WeiboMode *model=[[WeiboMode alloc]initWithDictionary:dictionary];
        NSString *text=[model.statuses[] objectForKey:@"text"];
        //更新UI需要回到主線程
        //    self.textView.text=text;
        //    [self.textView performSelectorOnMainThread:@selector(setText:) withObject:text waitUntilDone:NO];
        dispatch_async(dispatch_get_main_queue(), ^{
            self.textView.text =text;
        });
}
           
更新UI需要回到主線程的方式:

不推薦:

self.textView.text=text;

1.采用performSelectorOnMainThread方法

[self.textView performSelectorOnMainThread:@selector(setText:) withObject:text waitUntilDone:NO];
           

2. 開啟一個異步操作 dispatch_async

dispatch_async(dispatch_get_main_queue(), ^{
            self.textView.text =text;
        });
           

sendAsynchronousRequest方法(在completionHandler代碼塊中解析JSON資料)

此方法與sendSynchronousReques方法有所不同,其中有一個參數是代碼塊。(這裡有個小技巧是:我們可以在這個參數上按回車,Xcode會自動幫我們書寫正确的代碼塊格式)

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        NSDictionary *dictionary=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
        WeiboMode *model=[[WeiboMode alloc]initWithDictionary:dictionary];
        NSString *text=[model.statuses[0] objectForKey:@"text"];
        dispatch_async(dispatch_get_main_queue(), ^{
            self.textView.text=text;
        });
    }];
}
           

同步Post

- (IBAction)SynchronizationPost:(UIButton *)sender {
    NSString *[email protected]"https://api.weibo.com/2/statuses/update.json";
    //字元串編碼
    urlString =[urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSURL *url=[NSURL URLWithString:urlString];
    NSMutableURLRequest *mRequest=[NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:];
    NSString *bodyString = @"status=|這裡寫我們要輸入的文本資料接口|&access_token=|這裡寫我們擷取到的API接口的access_token|";
    NSData *data=[bodyString dataUsingEncoding:NSUTF8StringEncoding];
    //post 設定它的方法體
    [mRequest setHTTPMethod:@"POST"];
    [mRequest setHTTPBody:data];
    NSData *resultData=[NSURLConnection sendSynchronousRequest:mRequest returningResponse:nil error:nil];
    NSDictionary *dictionary=[NSJSONSerialization JSONObjectWithData:resultData options:NSJSONReadingAllowFragments error:nil];
    NSLog(@"dictionary= %@",dictionary);

}
           

異步Post

- (IBAction)AynchronizationPost:(UIButton *)sender {
    NSString *[email protected]"https://api.weibo.com/2/statuses/update.json";
    //字元串編碼
    urlString =[urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSURL *url=[NSURL URLWithString:urlString];
    NSMutableURLRequest *mRequest=[NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:];
    NSString *bodyString = @"status=|這裡寫我們要輸入的文本資料接口|&access_token=|這裡寫我們擷取到的API接口的access_token|";
    NSData *data=[bodyString dataUsingEncoding:NSUTF8StringEncoding];
    [mRequest setHTTPMethod:@"POST"];
    [mRequest setHTTPBody:data];
    _connectionPost=[NSURLConnection connectionWithRequest:mRequest delegate:self];
           

将get和post的同時寫到NSURLConnectionDataDelegate協定代理的方法中

#pragma mark  -------NSURLConnectionDataDelegate-------
//伺服器開始響應,準備向客戶發送資料
-(void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response{
    NSLog(@"伺服器開始響應,準備向客戶發送資料");
    if (connection ==_connectionGet) {
        _mDataGet=[NSMutableData data];
    }
    if (connection == _connectionPost) {
        _mDataPost=[NSMutableData data];
    }
}
-(void)connection:(NSURLConnection *)connection
   didReceiveData:(NSData *)data{
    NSLog(@"從伺服器接收到資料,并且此方法會執行多次");
    if (connection ==_connectionGet) {

        [_mDataGet appendData:data];
    }
    if (connection ==_connectionPost) {
        [_mDataPost appendData:data];
    }
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection{ NSLog(@"伺服器接收資料完成");
    if (connection == _connectionGet) {
        NSDictionary *dictionary=[NSJSONSerialization JSONObjectWithData:_mDataGet options:NSJSONReadingAllowFragments error:nil];
        WeiboMode *model=[[WeiboMode alloc]initWithDictionary:dictionary];
        NSString *text=[model.statuses[] objectForKey:@"text"];
        //更新UI需要回到主線程
        //    self.textView.text=text;
        //    [self.textView performSelectorOnMainThread:@selector(setText:) withObject:text waitUntilDone:NO];
        dispatch_async(dispatch_get_main_queue(), ^{
            self.textView.text =text;
        });
    }
    if (connection == _connectionPost) {
        NSDictionary *dictionary=[NSJSONSerialization JSONObjectWithData:_mDataPost options:NSJSONReadingAllowFragments error:nil];
        NSLog(@"dictionary = %@",dictionary);
    }
}
@end