開發(fā)只懂 AFN ?搞定 NSURLSession 才是硬道理

目錄

NSURLSession 的優(yōu)勢

NSURLSessionTask 的子類

NSURLSessionDataTask 發(fā)送 GET 請求

NSURLSessionDataTask 發(fā)送 POST 請求

NSURLSessionDataTask 設(shè)置代理發(fā)送請求

設(shè)置代理之后的強引用問題

NSURLSessionDataTask 簡單下載

NSURLSessionDownloadTask 簡單下載

dataTask 和 downloadTask 下載對比

寫在最后

【補充】NSURLSession 詳解離線斷點下載的實現(xiàn)

NSURLSession 的優(yōu)勢

NSURLSession 支持 http2.0 協(xié)議

在處理下載任務(wù)的時候可以直接把數(shù)據(jù)下載到磁盤

支持后臺下載|上傳

同一個 session 發(fā)送多個請求,只需要建立一次連接(復(fù)用了TCP)

提供了全局的 session 并且可以統(tǒng)一配置,使用更加方便

下載的時候是多線程異步處理,效率更高

NSURLSessionTask 的子類

NSURLSessionTask 是一個抽象類,如果要使用那么只能使用它的子類

NSURLSessionTask 有兩個子類

NSURLSessionDataTask,可以用來處理一般的網(wǎng)絡(luò)請求,如 GET | POST 請求等

NSURLSessionDataTask 有一個子類為 NSURLSessionUploadTask,用于處理上傳請求的時候有優(yōu)勢

NSURLSessionDownloadTask,主要用于處理下載請求,有很大的優(yōu)勢

NSURLSession 的子類

NSURLSessionDataTask 發(fā)送 GET 請求

發(fā)送 GET 請求的步驟非常簡單,只需要兩步就可以完成:

使用 NSURLSession 對象創(chuàng)建 Task

執(zhí)行 Task

//確定請求路徑NSURL*url = [NSURLURLWithString:@"http://120.25.226.186:32812/login?username=520&pwd=520&type=JSON"];//創(chuàng)建 NSURLSession 對象NSURLSession*session = [NSURLSessionsharedSession];/**

根據(jù)對象創(chuàng)建 Task 請求

url? 方法內(nèi)部會自動將 URL 包裝成一個請求對象(默認(rèn)是 GET 請求)

completionHandler? 完成之后的回調(diào)(成功或失敗)

param data? ? 返回的數(shù)據(jù)(響應(yīng)體)

param response 響應(yīng)頭

param error? ? 錯誤信息

*/NSURLSessionDataTask*dataTask = [session dataTaskWithURL:url completionHandler:? ? ? ? ? ? ^(NSData* _Nullable data,NSURLResponse* _Nullable response,NSError* _Nullable error) {//解析服務(wù)器返回的數(shù)據(jù)NSLog(@"%@", [[NSStringalloc] initWithData:data encoding:NSUTF8StringEncoding]);//默認(rèn)在子線程中解析數(shù)據(jù)NSLog(@"%@", [NSThreadcurrentThread]); }];//發(fā)送請求(執(zhí)行Task)[dataTask resume];

NSURLSessionDataTask 發(fā)送 POST 請求

發(fā)送 POST 請求的步驟與發(fā)送 GET 請求一樣:

使用 NSURLSession 對象創(chuàng)建 Task

執(zhí)行 Task

//確定請求路徑NSURL*url = [NSURLURLWithString:@"http://120.25.226.186:32812/login"];//創(chuàng)建可變請求對象NSMutableURLRequest*requestM = [NSMutableURLRequestrequestWithURL:url];//修改請求方法requestM.HTTPMethod=@"POST";//設(shè)置請求體requestM.HTTPBody= [@"username=520&pwd=520&type=JSON"dataUsingEncoding:NSUTF8StringEncoding];//創(chuàng)建會話對象NSURLSession*session = [NSURLSessionsharedSession];//創(chuàng)建請求 TaskNSURLSessionDataTask*dataTask = [session dataTaskWithRequest:requestM completionHandler:? ? ? ? ? ? ^(NSData* _Nullable data,NSURLResponse* _Nullable response,NSError* _Nullable error) {//解析返回的數(shù)據(jù)NSLog(@"%@", [[NSStringalloc] initWithData:data encoding:NSUTF8StringEncoding]); }];//發(fā)送請求[dataTask resume];

NSURLSessionDataTask 設(shè)置代理發(fā)送請求

創(chuàng)建 NSURLSession 對象設(shè)置代理

使用 NSURLSession 對象創(chuàng)建 Task

執(zhí)行 Task

//確定請求路徑NSURL*url = [NSURLURLWithString:@"http://120.25.226.186:32812/login"];//創(chuàng)建可變請求對象NSMutableURLRequest*requestM = [NSMutableURLRequestrequestWithURL:url];//設(shè)置請求方法requestM.HTTPMethod=@"POST";//設(shè)置請求體requestM.HTTPBody= [@"username=520&pwd=520&type=JSON"dataUsingEncoding:NSUTF8StringEncoding];//創(chuàng)建會話對象,設(shè)置代理/**

第一個參數(shù):配置信息

第二個參數(shù):設(shè)置代理

第三個參數(shù):隊列,如果該參數(shù)傳遞nil 那么默認(rèn)在子線程中執(zhí)行

*/NSURLSession*session = [NSURLSessionsessionWithConfiguration:[NSURLSessionConfigurationdefaultSessionConfiguration]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? delegate:selfdelegateQueue:nil];//創(chuàng)建請求 TaskNSURLSessionDataTask*dataTask = [session dataTaskWithRequest:requestM];//發(fā)送請求[dataTask resume];

遵守協(xié)議,實現(xiàn)代理方法(常用的有三種代理方法)

-(void)URLSession:(NSURLSession*)session dataTask:(nonnullNSURLSessionDataTask*)dataTask didReceiveResponse:(nonnullNSURLResponse*)response completionHandler:(nonnullvoid(^)(NSURLSessionResponseDisposition))completionHandler {//子線程中執(zhí)行NSLog(@"接收到服務(wù)器響應(yīng)的時候調(diào)用 -- %@", [NSThreadcurrentThread]);self.dataM= [NSMutableDatadata];//默認(rèn)情況下不接收數(shù)據(jù)//必須告訴系統(tǒng)是否接收服務(wù)器返回的數(shù)據(jù)completionHandler(NSURLSessionResponseAllow);}-(void)URLSession:(NSURLSession*)session dataTask:(NSURLSessionDataTask*)dataTask didReceiveData:(NSData*)data {NSLog(@"接受到服務(wù)器返回數(shù)據(jù)的時候調(diào)用,可能被調(diào)用多次");//拼接服務(wù)器返回的數(shù)據(jù)[self.dataMappendData:data];}-(void)URLSession:(NSURLSession*)session task:(NSURLSessionTask*)task didCompleteWithError:(NSError*)error {NSLog(@"請求完成或者是失敗的時候調(diào)用");//解析服務(wù)器返回數(shù)據(jù)NSLog(@"%@", [[NSStringalloc] initWithData:self.dataMencoding:NSUTF8StringEncoding]);}

設(shè)置代理之后的強引用問題

NSURLSession 對象在使用的時候,如果設(shè)置了代理,那么 session 會對代理對象保持一個強引用,在合適的時候應(yīng)該主動進(jìn)行釋放

可以在控制器調(diào)用 viewDidDisappear 方法的時候來進(jìn)行處理,可以通過調(diào)用 invalidateAndCancel 方法或者是 finishTasksAndInvalidate 方法來釋放對代理對象的強引用

invalidateAndCancel 方法直接取消請求然后釋放代理對象

finishTasksAndInvalidate 方法等請求完成之后釋放代理對象。

[self.sessionfinishTasksAndInvalidate];

NSURLSessionDataTask 簡單下載

在前面請求數(shù)據(jù)的時候就相當(dāng)于一個簡單的下載過程,NSURLSessionDataTask 下載文件具體的步驟與上類似:

使用 NSURLSession 對象創(chuàng)建一個 Task 請求

執(zhí)行請求

[[[NSURLSessionsharedSession] dataTaskWithURL:[NSURLURLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"]? ? ? completionHandler:^(NSData* _Nullable data,NSURLResponse* _Nullable response,NSError* _Nullable error) {//解析數(shù)據(jù)UIImage*image = [UIImageimageWithData:data];//回到主線程設(shè)置圖片dispatch_async(dispatch_get_main_queue(), ^{self.imageView.image= image;? ? }); }] resume];

NSURLSessionDownloadTask 簡單下載

使用 NSURLSession 對象創(chuàng)建下載請求

在下載請求中移動文件到指定位置

執(zhí)行請求

//確定請求路徑NSURL*url = [NSURLURLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"];//創(chuàng)建請求對象NSURLRequest*request = [NSURLRequestrequestWithURL:url];//創(chuàng)建會話對象NSURLSession*session = [NSURLSessionsharedSession];//創(chuàng)建會話請求//優(yōu)點:該方法內(nèi)部已經(jīng)完成了邊接收數(shù)據(jù)邊寫沙盒的操作,解決了內(nèi)存飆升的問題NSURLSessionDownloadTask*downTask = [session downloadTaskWithRequest:request? ? ? completionHandler:^(NSURL* _Nullable location,NSURLResponse* _Nullable response,NSError* _Nullable error) {//默認(rèn)存儲到臨時文件夾 tmp 中,需要剪切文件到 cacheNSLog(@"%@", location);//目標(biāo)位置NSString*fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES) lastObject]? ? ? ? ? ? ? ? ? ? ? ? ? stringByAppendingPathComponent:response.suggestedFilename];/**

fileURLWithPath:有協(xié)議頭

URLWithString:無協(xié)議頭

*/[[NSFileManagerdefaultManager] moveItemAtURL:location toURL:[NSURLfileURLWithPath:fullPath] error:nil]; }];//發(fā)送請求[downTask resume];

以上方法無法監(jiān)聽下載進(jìn)度,如要獲取下載進(jìn)度,可以使用代理的方式進(jìn)行下載。

dataTask 和 downloadTask 下載對比

NSURLSessionDataTask

下載文件可以實現(xiàn)離線斷點下載,但是代碼相對復(fù)雜

NSURLSessionDownloadTask

下載文件可以實現(xiàn)斷點下載,但不能離線斷點下載

內(nèi)部已經(jīng)完成了邊接收數(shù)據(jù)邊寫入沙盒的操作

解決了下載大文件時的內(nèi)存飆升問題

寫在最后

關(guān)于使用 NSURLSession 進(jìn)行上傳文件操作,我只想說真的很麻煩,建議大家時間充沛且有興趣的可以研究一下,如果不想研究也是可以的,繼續(xù)使用我們偉大的 AFN 框架就好。至于 AFN 框架的使用,這里就不贅述了,后期如果有時間會更新一些常用的 AFN 使用方法,敬請期待。

附:使用 NSURLSession 上傳文件主要步驟及注意點

主要步驟:

確定上傳請求的路徑( NSURL )

創(chuàng)建可變的請求對象( NSMutableURLRequest )

修改請求方法為 POST

設(shè)置請求頭信息(告知服務(wù)器端這是一個文件上傳請求)

按照固定的格式拼接要上傳的文件等參數(shù)

根據(jù)請求對象創(chuàng)建會話對象( NSURLSession 對象)

根據(jù) session 對象來創(chuàng)建一個 uploadTask 上傳請求任務(wù)

執(zhí)行該上傳請求任務(wù)(調(diào)用 resume 方法)

得到服務(wù)器返回的數(shù)據(jù),解析數(shù)據(jù)(上傳成功 | 上傳失敗)

注意點:

創(chuàng)建可變的請求對象,因為需要修改請求方法為 POST,設(shè)置請求頭信息

設(shè)置請求頭這個步驟可能會被遺漏

要處理上傳參數(shù)的時候,一定要按照固定的格式來進(jìn)行拼接

需要采用合適的方法來獲得上傳文件的二進(jìn)制數(shù)據(jù)類型( MIMEType,獲取方式如下)

點擊這里搜索

對著該文件發(fā)送一個網(wǎng)絡(luò)請求,接收到該請求響應(yīng)的時候,可以通過響應(yīng)頭信息中的 MIMEType 屬性得到

使用通用的二進(jìn)制數(shù)據(jù)類型表示任意的二進(jìn)制數(shù)據(jù) application/octet-stream

調(diào)用 C 語言的 API 來獲取

[self mimeTypeForFileAtPath:@"此處為上傳文件的路徑"]

文/Mortal_Master(簡書作者)

原文鏈接:http://www.lxweimin.com/p/b0ddadd34037

著作權(quán)歸作者所有,轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),并標(biāo)注“簡書作者”。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容