前言
雲計算
近幾年來,雲計算是一個非常熱門的技術名詞,很多專家認為,雲計算會改變互聯網的技術基礎,甚至會影響整個產業的格局。可能還很多人不了解什么是雲計算,簡單來說,就是把用戶的數據(比如文檔、照片等)、用戶需要使用的軟件、用戶需要搜索的資源都保存在"雲端",並不用保存在用戶本地。你可以將"雲端"看做了一台超級計算機,其實是由無數台大型服務器組成的。
移動應用
現在很多的移動應用也類似於"雲計算"的模式,比如新浪微博,用戶的數據都是保存在新浪服務器的數據庫里面。當用戶想在手機上看到自己的微博數據時,大致需要以下幾個過程:
1.新浪微博手機客戶端發送HTTP請求到新浪服務器
2.服務器響應后返回數據給客戶端
3.客戶端對數據進行解析后以圖形界面的形式(如列表形式)呈現給用戶
網絡處理這一塊在移動開發中占據着非常重要的地位,我們這個專題主要來學習iOS網絡處理中的HTTP請求。
一、API簡介
如果你想在iOS中發送Http請求的話,有很多方式可以選擇,我在這里介紹幾個常見的:
1.蘋果自帶的API
1> Core Foundation框架中的CFNetwork API:純C語言的API,性能非常高
2> Foundation框架中的NSURLConnection API:Objective-C的API,性能也不錯,簡單易用
2.第3方開源框架
2> AFNetworking
我們這個專題主要來研究NSURLConnection的使用,至於第3方框架的學習,網上也有很多資源可以搜索。
二、發送異步的GET請求
眾所周知,HTTP的主要請求方式有2種:GET請求和POST請求,接下來先演示下如何發送一個GET請求。
需要注意的是,你最好發送一個異步請求,不要發送同步請求。iOS程序啟動后,系統會默認創建一條主線程,也稱為UI線程,這條主線程專門用來渲染UI界面、處理UI界面和用戶之間的交互,比如處理用戶的觸摸事件、文本輸入事件等。所謂異步請求,就是在后台線程發送請求,不在主線程發送請求。一般情況下,客戶端發出請求后,需要等待服務器的數據返回,如果服務器處理速度比較慢或者網速慢的話,可能要等很長時間。因此,如果你執意要發送同步請求,也就是在主線程發送請求,會造成主線程阻塞,容易出現卡機現象,給用戶帶來極差的體驗。
1.利用NSURLConnection發送異步請求
1 // 請求地址 2 NSString *urlString = @"http://192.168.1.102:8080/MJServer/login?username=123&pwd=123"; 3 4 // 初始化一個NSURL對象 5 NSURL *url = [NSURL URLWithString:urlString]; 6 7 // 初始化一個請求 8 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 9 // 設置請求方法,可以省略,默認就是GET請求 10 request.HTTPMethod = @"GET"; 11 // 如果60秒過后服務器還沒有相應,就算請求超時 12 request.timeoutInterval = 60; 13 14 // 初始化一個連接 15 NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self]; 16 // 開始一個異步請求 17 [conn start];
1> 第2行的是請求地址,由於是GET請求,請求參數是直接拼接到路徑后面的
2> 第17行調用NSURLConnection的start方法發送一個HTPP請求,默認就是異步請求
2.NSURLConnectionDataDelegate
在前面的第15行代碼中,初始化NSURLConnection對象的時候傳了個self做代理(delegate),我這里的self是控制器。在客戶端跟服務器交互過程會不斷地給這個代理對象發送消息,也就是會不斷地調用代理對象的相應方法。iOS在NSURLConnectionDataDelegate協議中定義了很多代理方法,我這里只介紹常用的3個方法:
1 #pragma mark - NSURLConnectionDataDelegate 2 #pragma mark 接收到服務器返回的數據時調用(如果數據比較多,這個方法可能會被調用多次) 3 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 4 NSLog(@"接收到服務器返回的數據"); 5 // 拼接數據 6 [self.data appendData:data]; 7 } 8 9 #pragma mark 網絡連接出錯時調用 10 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 11 NSLog(@"網絡連接出錯:%@", [error localizedDescription]); 12 } 13 14 #pragma mark 服務器的數據已經接收完畢時調用 15 - (void)connectionDidFinishLoading:(NSURLConnection *)connection { 16 NSLog(@"服務器的數據已經接收完畢"); 17 // 解析成字符串數據 18 NSString *str = [[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding] autorelease]; 19 NSLog(@"%@", str); 20 }
1> 當服務器有數據返回時就會調用第3行的代理方法,返回的數據以NSData的格式傳入。如果數據比較多,比如下載大文件時,這個方法可能會被調用多次。
2> 第6行用一個NSMutableData對象拼接服務器返回的所有數據,self.data是一個NSMutableData。
3> 當服務器已經成功返回所有的數據后,會調用第15行的代理方法,到此為止,self.data里面存放着服務器端返回的所有數據
4> 由於我這邊服務器返回的是JSON字符串數據,所以在18行將self.data轉換為NSString,然后打印出來看看數據對不對
3.對中文參數進行編碼
如果你的請求參數中含有中文,必須先進行編碼,然后再拼接到請求路徑后面。
下面的請求路徑寫法是錯誤的:
1 NSString *urlString = @"http://192.168.1.102:8080/MJServer/login?username=母雞";
應該這樣寫:
1 // 使用UTF-8對中文參數進行編碼 2 NSString *param = [@"母雞" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 3 4 // 請求地址 5 NSString *baseUrl = @"http://192.168.1.102:8080/MJServer/login?username="; 6 NSString *urlString = [baseUrl stringByAppendingString:param];
1> 第2行使用UTF-8對中文參數進行編碼
2> 在第6行拼接編碼后的參數到請求路徑中
4.取消請求
如果用戶的網絡狀況不是很好,那么在登錄的過程中,用戶很可能會點擊"取消"按鈕來取消登錄
當用戶點擊了取消按鈕,我們也應該終止之前發送的請求,這時候可以這樣做
[conn cancel];
conn是一個NSURLConnection對象