URL加載系統(tǒng)之三:NSURLConnection

NSURLConnection提供了簡單的接口來創(chuàng)建和取消一個連接,并支持一個代理方法的集合來提供連接的響應(yīng),并對連接進行多方面的控制。這個類的方法可以分為5大類:URL加載、緩存管理、認證與證書、cookie存儲、協(xié)議支持。

創(chuàng)建一個連接

NSURLConnection提供了三種方式來獲取URL的內(nèi)容:同步、異步使用完成處理器block、異步使用自定義的代理對象。

使用同步請求時,一般是在后臺線程中獨占線程運行,我們可以調(diào)用sendSynchronousRequest:returningResponse:error: 方法來執(zhí)行HTTP請求。當(dāng)請求完成或返回錯誤時,該方法會返回。

如果我們不需要監(jiān)聽請求的狀態(tài),而只是在數(shù)據(jù)完成返回時執(zhí)行一些操作,則可以調(diào)用sendAsynchronousRequest:queue:completionHandler:方法來執(zhí)行一個異步操作,其中需要傳遞一個block來處理結(jié)果。

我們也可以創(chuàng)建一個代理對象來處理異步請求,此時我們需要實現(xiàn)以下方法:connection:didReceiveResponse:、connection:didReceiveData:、connection:didFailWithError:和connectionDidFinishLoading: 。這些方法在NSURLConnectionDelegate、NSURLConnectionDownloadDelegate和 NSURLConnectionDataDelegate協(xié)議中定義。

代碼清單1以代理對象異步請求為例,初始化了一個URL連接并實現(xiàn)代理方法來處理連接響應(yīng)

@interface Conn : NSObject

{

NSURLConnection *theConnection;

NSMutableData *receivedData;

}

@end

@implementation Conn

- (void)createConnection

{

// 創(chuàng)建一個請求

NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.apple.com/"]

cachePolicy:NSURLRequestUseProtocolCachePolicy

timeoutInterval:60.0];

// 創(chuàng)建NSMutableData來保存接收到的數(shù)據(jù)

receivedData = [NSMutableData dataWithCapacity: 0];

// 使用theRequest創(chuàng)建一個連接并開始加載數(shù)據(jù)

// 調(diào)用initWithRequest:delegate后會立即開始傳輸

// 請求可以在connectionDidFinishLoading:或connection:didFailWithError:消息被發(fā)送前通過調(diào)用cancel來取消

theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

if (!theConnection) {

// 釋放receivedData對象

receivedData = nil;

// 通知用戶連接失敗

}

}

// 當(dāng)服務(wù)端提供了有效的數(shù)據(jù)來創(chuàng)建NSURLResponse對象時,代理會收到connection:didReceiveResponse:消息。

// 這個代理方法會檢查NSURLResponse對象并確認數(shù)據(jù)的content-type,MIME類型,文件 名和其它元數(shù)據(jù)。

// 需要注意的是,對于單個連接,我們可能會接多次收到connection:didReceiveResponse:消息;這咱情況發(fā)生在

// 響應(yīng)是多重MIME編碼的情況下。每次代理接收到connection:didReceiveResponse:時,應(yīng)該重設(shè)進度標(biāo)識

// 并丟棄之前接收到的數(shù)據(jù)。

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

{

[receivedData setLength:0];

}

// 代理會定期接收到connection:didReceiveData:消息,該消息用于接收服務(wù)端返回的數(shù)據(jù)實體。該方法負責(zé)存儲數(shù)據(jù)。

// 我們也可以用這個方法提供進度信息,這種情況下,我們需要在connection:didReceiveResponse:方法中

// 調(diào)用響應(yīng)對象的expectedContentLength方法來獲取數(shù)據(jù)的總長度。

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

{

[receivedData appendData:data];

}

// 如果數(shù)據(jù)傳輸?shù)倪^程中出現(xiàn)了錯誤,代理會接收到connection:didFailWithError:消息。其中error參數(shù)給出了錯誤信息。

// 在代理收到connection:didFailWithError:消息后,它不會再接收指定連接的代理消息。

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

{

theConnection = nil;

receivedData = nil;

NSLog(@"Connection failed! Error - %@ %@", [error localizedDescription], [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);

}

// 如果成功獲取服務(wù)端返回的所有數(shù)據(jù),則代理會收到connectionDidFinishLoading:消息。

- (void)connectionDidFinishLoading:(NSURLConnection *)connection

{

NSLog(@"Succeeded! Receive %lu bytes of data(unsigned long)",[receivedData length]);

theConnection = nil;

receivedData = nil;

}

@end

發(fā)起一個POST請求

我們可以像發(fā)起其它URL請求一樣,發(fā)起一個HTTP或HTTPS POST請求。主要的區(qū)別在于我們必須先配置好NSMutableURLRequest對象,并將其作為參數(shù)傳遞給initWithRequest:delegate:方法。

另外,我們還需要構(gòu)造請求的body數(shù)據(jù)??梢砸韵旅嫒N方式來處理

對于上傳短小的內(nèi)存數(shù)據(jù),我們需要對已存在的數(shù)據(jù)塊進行URL編碼

如果是從磁盤中上傳文件,則調(diào)用setHTTPBodyStream:方法來告訴NSMutableURLRequest從一個NSInputStream中讀取并使用結(jié)果數(shù)據(jù)作為body的內(nèi)容

對于大塊的數(shù)據(jù),調(diào)用CFStreamCreateBoundPair來創(chuàng)建流對象對,然后調(diào)用setHTTPBodyStream:方法來告訴NSMutableURLRequest使用這些流對象中的一個作為body內(nèi)容的源。通過將數(shù)據(jù)寫入其它流,可以一次發(fā)送一小塊數(shù)據(jù)。

如果要上傳數(shù)據(jù)到一個兼容的服務(wù)器中,URL加載系統(tǒng)同樣支持100(繼續(xù))狀態(tài)碼,這樣允許一個上傳操作在發(fā)生認證錯誤或其它失敗時仍能繼續(xù)。為了開啟這個操作,可以設(shè)置請求對象的expect頭為100-continue。

代碼清單2展示了如何配置一個POST請求的NSMutableURLRequest對象

- (void)setRequestForPost

{

// 對于application/x-www-form-urlencoded類型的body數(shù)據(jù),form域的參數(shù)由&號分開,

NSString *bodyData = @"name=Jane+Doe&address=123+Main+St";

NSMutableURLRequest *postRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://www.apple.com"]];

// 設(shè)置content-type為application/x-www-form-urlencoded

[postRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

// 指定請求方法為POST

[postRequest setHTTPMethod:@"POST"];

[postRequest setHTTPBody:[NSData dataWithBytes:[bodyData UTF8String] length:strlen([bodyData UTF8String])]];

// Initialize the NSURLConnection and proceed as described in

// Retrieving the Contents of a URL

}

使用Block來接收數(shù)據(jù)

NSURLConnection類提供了類方法sendAsynchronousRequest:queue:completionHandler:,該方法可以以異常的方式向服務(wù)端發(fā)起請求,并在數(shù)據(jù)返回或發(fā)生錯誤/超時時調(diào)用block來處理。該方法需要一個請求對象,一個完成處理block,及block運行的隊列。當(dāng)請求完成或錯誤發(fā)生時,URL加載系統(tǒng)調(diào)用該block來處理結(jié)果數(shù)據(jù)或錯誤信息。

如果請求成功,則會傳遞一個NSData對象和一個NSURLResponse對象給block。如果失敗,則傳遞一個NSError對象。

這個方法有兩個限制

對于需要認證的請求,只提供最小的支持。

沒有辦法來修改響應(yīng)緩存和服務(wù)端重定向的默認行為

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容