認(rèn)識(shí)NSURLSession

1.0 NSURLSession的基本使用

(1)使用步驟

    使用NSURLSession創(chuàng)建task,然后執(zhí)行task

(2)關(guān)于task

    a.NSURLSessionTask是一個(gè)抽象類,本身不能使用,只能使用它的子類
    b.NSURLSessionDataTask\NSURLSessionUploadTask\NSURLSessionDownloadTask

(3)發(fā)送get請(qǐng)求

    //1.創(chuàng)建NSURLSession對(duì)象(可以獲取單例對(duì)象)
    NSURLSession *session = [NSURLSession sharedSession];

    //2.根據(jù)NSURLSession對(duì)象創(chuàng)建一個(gè)Task

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=ss&pwd=ss&type=JSON"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    //方法參數(shù)說明
    /*
    注意:該block是在子線程中調(diào)用的,如果拿到數(shù)據(jù)之后要做一些UI刷新操作,那么需要回到主線程刷新
    第一個(gè)參數(shù):需要發(fā)送的請(qǐng)求對(duì)象
    block:當(dāng)請(qǐng)求結(jié)束拿到服務(wù)器響應(yīng)的數(shù)據(jù)時(shí)調(diào)用block
    block-NSData:該請(qǐng)求的響應(yīng)體
    block-NSURLResponse:存放本次請(qǐng)求的響應(yīng)信息,響應(yīng)頭,真實(shí)類型為NSHTTPURLResponse
    block-NSErroe:請(qǐng)求錯(cuò)誤信息
     */
   NSURLSessionDataTask * dataTask =  [session dataTaskWithRequest:request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) {

        //拿到響應(yīng)頭信息
        NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;

        //4.解析拿到的響應(yīng)數(shù)據(jù)
        NSLog(@"%@\n%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],res.allHeaderFields);
    }];

    //3.執(zhí)行Task
    //注意:剛創(chuàng)建出來的task默認(rèn)是掛起狀態(tài)的,需要調(diào)用該方法來啟動(dòng)任務(wù)(執(zhí)行任務(wù))
    [dataTask resume];

(4)發(fā)送get請(qǐng)求的第二種方式

  //注意:該方法內(nèi)部默認(rèn)會(huì)把URL對(duì)象包裝成一個(gè)NSURLRequest對(duì)象(默認(rèn)是GET請(qǐng)求)
    //方法參數(shù)說明
    /*
    //第一個(gè)參數(shù):發(fā)送請(qǐng)求的URL地址
    //block:當(dāng)請(qǐng)求結(jié)束拿到服務(wù)器響應(yīng)的數(shù)據(jù)時(shí)調(diào)用block
    //block-NSData:該請(qǐng)求的響應(yīng)體
    //block-NSURLResponse:存放本次請(qǐng)求的響應(yīng)信息,響應(yīng)頭,真實(shí)類型為NSHTTPURLResponse
    //block-NSErroe:請(qǐng)求錯(cuò)誤信息
     */
- (nullable NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error))completionHandler;

(5)發(fā)送POST請(qǐng)求

        //1.創(chuàng)建NSURLSession對(duì)象(可以獲取單例對(duì)象)
    NSURLSession *session = [NSURLSession sharedSession];

    //2.根據(jù)NSURLSession對(duì)象創(chuàng)建一個(gè)Task

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];

    //創(chuàng)建一個(gè)請(qǐng)求對(duì)象,并這是請(qǐng)求方法為POST,把參數(shù)放在請(qǐng)求體中傳遞
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"POST";
    request.HTTPBody = [@"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];

    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) {
        //拿到響應(yīng)頭信息
        NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;

        //解析拿到的響應(yīng)數(shù)據(jù)
        NSLog(@"%@\n%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],res.allHeaderFields);
    }];

    //3.執(zhí)行Task
    //注意:剛創(chuàng)建出來的task默認(rèn)是掛起狀態(tài)的,需要調(diào)用該方法來啟動(dòng)任務(wù)(執(zhí)行任務(wù))
    [dataTask resume];

2.0 NSURLSession下載文件-代理

(1)創(chuàng)建NSURLSession對(duì)象,設(shè)置代理(默認(rèn)配置)

 //1.創(chuàng)建NSURLSession,并設(shè)置代理
    /*
     第一個(gè)參數(shù):session對(duì)象的全局配置設(shè)置,一般使用默認(rèn)配置就可以
     第二個(gè)參數(shù):誰成為session對(duì)象的代理
     第三個(gè)參數(shù):代理方法在哪個(gè)隊(duì)列中執(zhí)行(在哪個(gè)線程中調(diào)用),如果是主隊(duì)列那么在主線程中執(zhí)行,如果是非主隊(duì)列,那么在子線程中執(zhí)行
     */
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

(2)根據(jù)Session對(duì)象創(chuàng)建一個(gè)NSURLSessionDataTask任務(wù)(post和get選擇)

//創(chuàng)建task
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"];

//注意:如果要發(fā)送POST請(qǐng)求,那么請(qǐng)使用dataTaskWithRequest,設(shè)置一些請(qǐng)求頭信息
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url];

(3)執(zhí)行任務(wù)(其它方法,如暫停、取消等)

    //啟動(dòng)task
    //[dataTask resume];
    //其它方法,如取消任務(wù),暫停任務(wù)等
    //[dataTask cancel];
    //[dataTask suspend];

(4)遵守代理協(xié)議,實(shí)現(xiàn)代理方法(3個(gè)相關(guān)的代理方法)

/*
 1.當(dāng)接收到服務(wù)器響應(yīng)的時(shí)候調(diào)用
     session:發(fā)送請(qǐng)求的session對(duì)象
     dataTask:根據(jù)NSURLSession創(chuàng)建的task任務(wù)
     response:服務(wù)器響應(yīng)信息(響應(yīng)頭)
     completionHandler:通過該block回調(diào),告訴服務(wù)器端是否接收返回的數(shù)據(jù)
 */
-(void)URLSession:(nonnull NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveResponse:(nonnull NSURLResponse *)response completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler

/*
 2.當(dāng)接收到服務(wù)器返回的數(shù)據(jù)時(shí)調(diào)用
 該方法可能會(huì)被調(diào)用多次
 */
-(void)URLSession:(nonnull NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveData:(nonnull NSData *)data

/*
 3.當(dāng)請(qǐng)求完成之后調(diào)用該方法
 不論是請(qǐng)求成功還是請(qǐng)求失敗都調(diào)用該方法,如果請(qǐng)求失敗,那么error對(duì)象有值,否則那么error對(duì)象為空
 */
-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error

(5)當(dāng)接收到服務(wù)器響應(yīng)的時(shí)候,告訴服務(wù)器接收數(shù)據(jù)(調(diào)用block)

//默認(rèn)情況下,當(dāng)接收到服務(wù)器響應(yīng)之后,服務(wù)器認(rèn)為客戶端不需要接收數(shù)據(jù),所以后面的代理方法不會(huì)調(diào)用
    //如果需要繼續(xù)接收服務(wù)器返回的數(shù)據(jù),那么需要調(diào)用block,并傳入對(duì)應(yīng)的策略

    /*
        NSURLSessionResponseCancel = 0, 取消任務(wù)
        NSURLSessionResponseAllow = 1,  接收任務(wù)
        NSURLSessionResponseBecomeDownload = 2, 轉(zhuǎn)變成下載
        NSURLSessionResponseBecomeStream NS_ENUM_AVAILABLE(10_11, 9_0) = 3, 轉(zhuǎn)變成流
    */

    completionHandler(NSURLSessionResponseAllow);

3.0 NSURLSessionDownloadTask實(shí)現(xiàn)大文件下載

(1)使用NSURLSession和NSURLSessionDownload可以很方便的實(shí)現(xiàn)文件下載操作

 /*
     第一個(gè)參數(shù):要下載文件的url路徑
     第二個(gè)參數(shù):當(dāng)接收完服務(wù)器返回的數(shù)據(jù)之后調(diào)用該block
     location:下載的文件的保存地址(默認(rèn)是存儲(chǔ)在沙盒中tmp文件夾下面,隨時(shí)會(huì)被刪除)
     response:服務(wù)器響應(yīng)信息,響應(yīng)頭
     error:該請(qǐng)求的錯(cuò)誤信息
     */
    //說明:downloadTaskWithURL方法已經(jīng)實(shí)現(xiàn)了在下載文件數(shù)據(jù)的過程中邊下載文件數(shù)據(jù),邊寫入到沙盒文件的操作
    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL * __nullable location, NSURLResponse * __nullable response, NSError * __nullable error)

(2)downloadTaskWithURL內(nèi)部默認(rèn)已經(jīng)實(shí)現(xiàn)了變下載邊寫入操作,所以不用開發(fā)人員擔(dān)心內(nèi)存問題

(3)文件下載后默認(rèn)保存在tmp文件目錄,需要開發(fā)人員手動(dòng)的剪切到合適的沙盒目錄

(4)缺點(diǎn):沒有辦法監(jiān)控下載進(jìn)度


4.0 使用NSURLSessionDownloadTask實(shí)現(xiàn)大文件下載-監(jiān)聽下載進(jìn)度

(1)創(chuàng)建NSURLSession并設(shè)置代理,通過NSURLSessionDownloadTask并以代理的方式來完成大文件的下載

     //1.創(chuàng)建NSULRSession,設(shè)置代理
    self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    //2.創(chuàng)建task
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
    self.downloadTask = [self.session downloadTaskWithURL:url];

    //3.執(zhí)行task
    [self.downloadTask resume];

(2)常用代理方法的說明

    /*
 1.當(dāng)接收到下載數(shù)據(jù)的時(shí)候調(diào)用,可以在該方法中監(jiān)聽文件下載的進(jìn)度
 該方法會(huì)被調(diào)用多次
 totalBytesWritten:已經(jīng)寫入到文件中的數(shù)據(jù)大小
 totalBytesExpectedToWrite:目前文件的總大小
 bytesWritten:本次下載的文件數(shù)據(jù)大小
 */
-(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
/*
 2.恢復(fù)下載的時(shí)候調(diào)用該方法
 fileOffset:恢復(fù)之后,要從文件的什么地方開發(fā)下載
 expectedTotalBytes:該文件數(shù)據(jù)的總大小
 */
-(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
/*
 3.下載完成之后調(diào)用該方法
 */
-(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location
/*
 4.請(qǐng)求完成之后調(diào)用
 如果請(qǐng)求失敗,那么error有值
 */
-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error

(3)實(shí)現(xiàn)斷點(diǎn)下載相關(guān)代碼

    //如果任務(wù),取消了那么以后就不能恢復(fù)了
    //    [self.downloadTask cancel];

    //如果采取這種方式來取消任務(wù),那么該方法會(huì)通過resumeData保存當(dāng)前文件的下載信息
    //只要有了這份信息,以后就可以通過這些信息來恢復(fù)下載
    [self.downloadTask cancelByProducingResumeData:^(NSData * __nullable resumeData) {
        self.resumeData = resumeData;
    }];

    -----------
    //繼續(xù)下載
    //首先通過之前保存的resumeData信息,創(chuàng)建一個(gè)下載任務(wù)
    self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];

     [self.downloadTask resume];

(4)計(jì)算當(dāng)前下載進(jìn)度

    //獲取文件下載進(jìn)度
    self.progress.progress = 1.0 * totalBytesWritten/totalBytesExpectedToWrite;

(5)局限性

01 如果用戶點(diǎn)擊暫停之后退出程序,那么需要把恢復(fù)下載的數(shù)據(jù)寫一份到沙盒,代碼復(fù)雜度更
02 如果用戶在下載中途未保存恢復(fù)下載數(shù)據(jù)即退出程序,則不具備可操作性

5.0 使用NSURLSessionDataTask實(shí)現(xiàn)大文件離線斷點(diǎn)下載(完整)

(1)關(guān)于NSOutputStream的使用

    //1. 創(chuàng)建一個(gè)輸入流,數(shù)據(jù)追加到文件的屁股上
    //把數(shù)據(jù)寫入到指定的文件地址,如果當(dāng)前文件不存在,則會(huì)自動(dòng)創(chuàng)建
    NSOutputStream *stream = [[NSOutputStream alloc]initWithURL:[NSURL fileURLWithPath:[self fullPath]] append:YES];

    //2. 打開流
    [stream open];

    //3. 寫入流數(shù)據(jù)
    [stream write:data.bytes maxLength:data.length];

    //4.當(dāng)不需要的時(shí)候應(yīng)該關(guān)閉流
    [stream close];

(2)關(guān)于網(wǎng)絡(luò)請(qǐng)求請(qǐng)求頭的設(shè)置(可以設(shè)置請(qǐng)求下載文件的某一部分)

    //1. 設(shè)置請(qǐng)求對(duì)象
    //1.1 創(chuàng)建請(qǐng)求路徑
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];

    //1.2 創(chuàng)建可變請(qǐng)求對(duì)象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    //1.3 拿到當(dāng)前文件的殘留數(shù)據(jù)大小
    self.currentContentLength = [self FileSize];

    //1.4 告訴服務(wù)器從哪個(gè)地方開始下載文件數(shù)據(jù)
    NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentContentLength];
    NSLog(@"%@",range);

    //1.5 設(shè)置請(qǐng)求頭
    [request setValue:range forHTTPHeaderField:@"Range"];

(3)NSURLSession對(duì)象的釋放

-(void)dealloc
{
    //在最后的時(shí)候應(yīng)該把session釋放,以免造成內(nèi)存泄露
    //    NSURLSession設(shè)置過代理后,需要在最后(比如控制器銷毀的時(shí)候)調(diào)用session的invalidateAndCancel或者resetWithCompletionHandler,才不會(huì)有內(nèi)存泄露
    //    [self.session invalidateAndCancel];
    [self.session resetWithCompletionHandler:^{

        NSLog(@"釋放---");
    }];
}

(4)優(yōu)化部分

    01 關(guān)于文件下載進(jìn)度的實(shí)時(shí)更新
    02 方法的獨(dú)立與抽取

6.NSURLSession實(shí)現(xiàn)文件上傳

(1)實(shí)現(xiàn)文件上傳的方法

      /*
     第一個(gè)參數(shù):請(qǐng)求對(duì)象
     第二個(gè)參數(shù):請(qǐng)求體(要上傳的文件數(shù)據(jù))
     block回調(diào):
     NSData:響應(yīng)體
     NSURLResponse:響應(yīng)頭
     NSError:請(qǐng)求的錯(cuò)誤信息
     */
    NSURLSessionUploadTask *uploadTask =  [session uploadTaskWithRequest:request fromData:data completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error)

(2)設(shè)置代理,在代理方法中監(jiān)聽文件上傳進(jìn)度

/*
 調(diào)用該方法上傳文件數(shù)據(jù)
 如果文件數(shù)據(jù)很大,那么該方法會(huì)被調(diào)用多次
 參數(shù)說明:
     totalBytesSent:已經(jīng)上傳的文件數(shù)據(jù)的大小
     totalBytesExpectedToSend:文件的總大小
 */
-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
    NSLog(@"%.2f",1.0 * totalBytesSent/totalBytesExpectedToSend);
}

(3)關(guān)于NSURLSessionConfiguration相關(guān)

01 作用:可以統(tǒng)一配置NSURLSession,如請(qǐng)求超時(shí)等
02 創(chuàng)建的方式和使用
//創(chuàng)建配置的三種方式
+ (NSURLSessionConfiguration *)defaultSessionConfiguration;
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier NS_AVAILABLE(10_10, 8_0);

//統(tǒng)一配置NSURLSession
-(NSURLSession *)session
{
    if (_session == nil) {

        //創(chuàng)建NSURLSessionConfiguration
        NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];

        //設(shè)置請(qǐng)求超時(shí)為10秒鐘
        config.timeoutIntervalForRequest = 10;

        //在蜂窩網(wǎng)絡(luò)情況下是否繼續(xù)請(qǐng)求(上傳或下載)
        config.allowsCellularAccess = NO;

        _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    }
    return _session;
}

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

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

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