Objective-C Http經常使用API 同步請求與異步請求

開發iOS應用要調用Http接口、獲取Http資源,有一套比較成熟的框架ASIHTTPRequest。而我仍是比較喜歡使用原始一點的 API,而它跟其餘的面嚮對象語言有許多共通之處。本文分同步請求和異步請求這兩種狀況來說解一下Http API的使用。直接上代碼,註釋即文檔!html

同步請求:即發起Http請求、獲取並處理返回值都在同一個線程中進行緩存

 

01. //建立URL對象
02. NSString *urlStr = @"http://blog.csdn.net/rongxinhua";
03. NSURL *url = [[NSURL alloc] initWithString:urlStr];
04.  
05. //建立HTTP請求
06. //方法1(注:NSURLRequest只支持Get請求,NSMutableURLRequest可支持Get和Post請求)
07. NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
08. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
09. //方法2,使用工廠方法建立
10. NSURLRequest *request = [NSURLRequest requestWithURL:url];
11. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
12. //同時設置緩存策略和超時時間
13. NSMutableURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15];
14.  
15. //設置Http頭
16. NSDictionary *headers = [request allHTTPHeaderFields];
17. [headers setValue:@"iOS-Client-ABC" forKey:@"User-Agent"];
18.  
19. //設置請求方法
20. [request setHTTPMethod:@"GET"];
21. [request setHTTPMethod:@"POST"];
22.  
23. //設置要發送的正文內容(適用於Post請求)
24. NSString *content = @"username=stanyung&pass<a href="http://www.it165.net/edu/ebg/" target="_blank" class="keylink">word</a>=123";
25. NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding];
26. [request setHTTPBody:data];
27.  
28. //同步執行Http請求,獲取返回數據
29. NSURLResponse *response;
30. NSError *error;
31. NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
32.  
33. //返數據轉成字符串
34. NSString *html = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
35.  
36. //(若是有錯誤)錯誤描述
37. NSString *errorDesc = [error localizedDescription];
38.  
39. //獲取狀態碼和HTTP響應頭信息
40. NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
41. NSInteger statusCode = [httpResponse statusCode];
42. NSDictionary *responseHeaders = [httpResponse allHeaderFields];
43. NSString *cookie = [responseHeaders valueForKey:@"Set-Cookie"];

注:以上代碼,不要Copy直接執行,只是列舉Http經常使用方法的調用。cookie

 

異步請求:發起HTTP請求在一個線程中,返回結果處理在另外一個線程中。相比同步請求,異步請求不須要等待返回結果,當前程序能夠繼續往下執行。在Objective-C中,異步請求也有兩種實現方式:一種是註冊回調代理,一種是使用回調代碼塊。網絡

 

a.註冊回調代理的方式:app

 

1. [NSURLConnection connectionWithRequest:request delegate:self];

 

須要實現NSURLConnectionDataDelegate協議:框架

 

1. @interface HttpDownloadService : NSObject<NSURLConnectionDataDelegate> {  
2. }

 

實現相關的協議方法:異步

 

01. NSMutableData *buff;    //暫存響應的數據
02. bool finished = false//讀完完整標記
03.  
04. //收到HTTP響應時調用
05. -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
06. NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
07. NSDictionary *headers = [httpResponse allHeaderFields];
08. buff = [[NSMutableData alloc] init];
09. }
10.  
11. //讀取返回數據時調用(可能會執行屢次此方法)
12. -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
13. [buff appendData:data];
14. }
15.  
16. //讀完數據完成時調用
17. -(void)connectionDidFinishLoading:(NSURLConnection *)connection {
18. NSString *html = [[NSString alloc] initWithData:buff encoding:NSUTF8StringEncoding];
19. finished = true;
20. }

 

一般狀況下,數據在網絡中傳輸,會受到帶寬等因素的影響,並不會一次情將全部數據返回,你可能分幾回才能接受完整一個HTTP響應報文。所以, (void)connection:(NSURLConnection *)didReceiveData:(NSData *) 這個方法極可能會執行屢次。函數

上例代碼中,使用了NSMutableData來暫存接收到的響應數據片斷,每一段並接起來,直到讀取完整。oop

b.使用回調代碼塊的方式:測試

 

1. [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:
2. ^(NSURLResponse *response, NSData *result, NSError *error){       //只會進入一次,方法內部已經實現了Buffer做用
3. NSString *html = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
4. }];

跟NSURLConnectionDataDelegate的回調方法不一樣,這裏的回調代碼塊只調用一次,它內部已經實現了Buffer的做用,等到數據接收完整後才進入此代碼塊。所以,你在代碼塊中獲取到的result能夠直接使用。

 

備註1:本文的代碼例子將使用ARC編碼模式,故所新建的對象均沒有顯式調用release()方法回收。

備註2:若你測試本例子代碼新建的是Command Line Tool工程,在main函數中執行相關代碼,上面兩種異步執行的狀況,你極可能你的程序沒有執行到回調方法或回調代碼塊裏面去,這是由於:在main函 數中,主線程沒有等待阻塞,一會兒執行完了,回調代碼所在的子線程可能未執行完或者根本還沒開始執行,就已經由於主線程的結束而結束了。解決這個問題,可 以在調用完異步方法後面,加如下代碼:

 

1. while (!finished) {
2. [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
3. }

而finished變量正是上面兩個異步HTTP例子中定義是否執行完成的變量。

相關文章
相關標籤/搜索