目錄
NSURLSession 的優(yōu)勢
NSURLSessionTask 的子類
NSURLSessionDataTask 發(fā)送 GET 請求
NSURLSessionDataTask 發(fā)送 POST 請求
NSURLSessionDataTask 設(shè)置代理發(fā)送請求
設(shè)置代理之后的強引用問題
NSURLSessionDataTask 簡單下載
NSURLSessionDownloadTask 簡單下載
dataTask 和 downloadTask 下載對比
寫在最后
【補充】NSURLSession 詳解離線斷點下載的實現(xiàn)
NSURLSession 支持 http2.0 協(xié)議
在處理下載任務(wù)的時候可以直接把數(shù)據(jù)下載到磁盤
支持后臺下載|上傳
同一個 session 發(fā)送多個請求,只需要建立一次連接(復(fù)用了TCP)
提供了全局的 session 并且可以統(tǒng)一配置,使用更加方便
下載的時候是多線程異步處理,效率更高
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]);}
NSURLSession 對象在使用的時候,如果設(shè)置了代理,那么 session 會對代理對象保持一個強引用,在合適的時候應(yīng)該主動進(jìn)行釋放
可以在控制器調(diào)用 viewDidDisappear 方法的時候來進(jìn)行處理,可以通過調(diào)用 invalidateAndCancel 方法或者是 finishTasksAndInvalidate 方法來釋放對代理對象的強引用
invalidateAndCancel 方法直接取消請求然后釋放代理對象
finishTasksAndInvalidate 方法等請求完成之后釋放代理對象。
[self.sessionfinishTasksAndInvalidate];
在前面請求數(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];
使用 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)行下載。
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)注“簡書作者”。