NSURLSession系列(三)-請(qǐng)求過程

前兩節(jié)完成了NSURLSession的創(chuàng)建。這一節(jié)的主要目的是通過Session創(chuàng)建NSURLSessionDataTask,完成通信交換并分析整個(gè)通信過程。分為以下幾個(gè)步驟:

  1. NSURLSessionDataTask的創(chuàng)建;
  2. 請(qǐng)求的發(fā)送和取消
  3. 請(qǐng)求過程的分析

1 創(chuàng)建NSURLSessionTask

蘋果供提供了5中SessionTask,其關(guān)系如下:


SessionTask關(guān)系圖
SessionTask關(guān)系圖

其中NSURLSessionTask是不能承接數(shù)據(jù)發(fā)送任務(wù)的。我們最常用的就是NSURLSessionDataTask。在上一節(jié)分析NSURLSession時(shí)已經(jīng)講到過有兩種方式創(chuàng)建NSURLSessionDataTask。分別是以block和delegate接受數(shù)據(jù)。NSURLSession給我們提供了很多的方法來完成這件事,這里就挑幾個(gè)我們常用的來稍微說明下:

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;

上面這四個(gè)方法是我們最常用的用來生成NSURLSessionDataTask的方法。比較清楚不再贅述。

2 請(qǐng)求的發(fā)送和取消

請(qǐng)求的發(fā)送很簡(jiǎn)單,只有一個(gè)方法resume。task對(duì)象生成后只有調(diào)用該方法才能把請(qǐng)求發(fā)送出去。方法如下:

// NSURLSessionTask
- (void)resume;

2 取消請(qǐng)求

請(qǐng)求的取消分為兩個(gè)層面:NSURLSessionTask層暫停和取消當(dāng)次任務(wù);NURLSession層停止整個(gè)session的請(qǐng)求。

2.1 暫停取消當(dāng)次任務(wù)

這里有兩個(gè)方法:suspend,cancel。

// NSURLSessionTask
- (void)suspend;
- (void)cancel;

suspend是暫停當(dāng)次任務(wù)。會(huì)停止當(dāng)次任務(wù)的傳輸,同時(shí),task處于暫停狀態(tài)期間,它的timeout屬性會(huì)暫時(shí)失效。
cancel會(huì)立即返回,它會(huì)停止數(shù)據(jù)的發(fā)送和接受。

2.2 停止session

一個(gè)session上可以有多個(gè)數(shù)據(jù)請(qǐng)求,如果停止了session,那么其上的所有請(qǐng)求都將失效。這里有兩個(gè)方法:

// NSURLSession
- (void)invalidateAndCancel;
- (void)finishTasksAndInvalidate;

這里就有個(gè)問題,何時(shí)停掉session?如果一個(gè)session上只要一個(gè)數(shù)據(jù)請(qǐng)求任務(wù),當(dāng)然可以任務(wù)結(jié)束時(shí)就停掉session。但是如果一個(gè)session上有多個(gè)任務(wù),那么何時(shí)停掉session就會(huì)是個(gè)問題。因?yàn)閟ession如果不停掉,那么它將會(huì)一直持有delegate。這個(gè)問題會(huì)在后面討論,以及session的內(nèi)存管理問題。

3 處理請(qǐng)求過程

請(qǐng)求處理的過程其實(shí)就是delegate調(diào)用的過程。delegate有兩種分類方法:1,按類別分類;2,按功能分類。第一種是官方的,第二種是我自己分的。
按類別分為5類:

  1. NSURLSessionDelegate
  2. NSURLSessionTaskDelegate
  3. NSURLSessionDataDelegate
  4. NSURLSessionDownloadDelegate
  5. NSURLSessionStreamDelegate

關(guān)系圖如下:


SessionTaskDelegate關(guān)系圖
SessionTaskDelegate關(guān)系圖

這種分類是控制層級(jí)由大到小。NSURLSessionDelegate控制session通道的建立,比如SSL通道的建立。NSURLSessionTaskDelegate控制請(qǐng)求任務(wù)的公共屬性,比如重定向、請(qǐng)求進(jìn)度、請(qǐng)求結(jié)束。后面三個(gè)每一種請(qǐng)求任務(wù)中獨(dú)有的屬性,比如NSURLSessionDataDelegate中要接收請(qǐng)求的進(jìn)度,NSURLSessionDownloadDelegate要處理下載完成的任務(wù)。
按功能分類,可以分類三種:認(rèn)證相關(guān)的delegate,常用的delegate和不常用的delegate。
認(rèn)證相關(guān)的delegate單獨(dú)在認(rèn)證的時(shí)候環(huán)節(jié)分析,這里只看一下常用的delegate。

3.1 常用sessiondelegate

共有5個(gè)常用的sessiondelegate。其中有NSURLSessionTaskDelegate有兩個(gè),如下:

// 方法1,決定重定向是否繼續(xù)
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
        newRequest:(NSURLRequest *)request
 completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler {
    // 如需要重定向請(qǐng)求就調(diào)用completionHandlercompletionHandler
    if (completionHandler) {
        completionHandler(request);
    }
}
// 方法2,請(qǐng)求完成
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error {
    // 每個(gè)次datatask完成都會(huì)調(diào)用此方法
}

NSURLSessionDataDelegate有三個(gè),如下:

// 方法3,收到響應(yīng)頭
- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler{
    // 處理完響應(yīng)頭,如先繼續(xù)請(qǐng)求,一定要調(diào)用
    if (completionHandler) {
        completionHandler(NSURLSessionResponseAllow);
    }
}
// 方法4,收到數(shù)據(jù),可能調(diào)用多次
- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data{
    // 接收響應(yīng)體,可能會(huì)調(diào)用多次
}
// 方法5,否需要cache請(qǐng)求
- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
 willCacheResponse:(NSCachedURLResponse *)proposedResponse
 completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler{
    // completionHandler必須要調(diào)用,如不想緩存completionHandler的參數(shù)傳null
    if (completionHandler) {
        completionHandler(proposedResponse);
    }
}

他們大致的職責(zé)范圍是:NSURLSessionTaskDelegate控制一個(gè)請(qǐng)求的開始和結(jié)束,NSURLSessionDataDelegate控制數(shù)據(jù)交換過程。
其中方法1只有在請(qǐng)求發(fā)生重定向時(shí)才會(huì)被調(diào)用,如果想要重定向請(qǐng)求,則需要調(diào)用completionHandler,參數(shù)是newRequest。否則,不能重定向請(qǐng)求。任何請(qǐng)求結(jié)束時(shí)都會(huì)調(diào)用方法2。當(dāng)收到http請(qǐng)求的應(yīng)答頭,即response head時(shí)就會(huì)調(diào)用方法3。其中response就是http的響應(yīng)頭。處理完響應(yīng)頭,如果想繼續(xù)請(qǐng)求需要調(diào)用completionHandler,否則請(qǐng)求將不會(huì)繼續(xù)。http的響應(yīng)體數(shù)據(jù)將會(huì)在方法4中收到,方法4可能不止調(diào)用一次。方法5涉及到緩存,這個(gè)就比較麻煩了。數(shù)據(jù)接收完成后會(huì)調(diào)用這個(gè)方法。這個(gè)方法的completionHander必須要調(diào)用,否則會(huì)引起內(nèi)存泄漏,具體為什么蘋果沒說,只是說必須要調(diào)用。這個(gè)方法的目的是改變某一個(gè)URL的緩存,比如不想緩存的話completionHander的參數(shù)傳NULL。或者是該變NSCachedURLResponse的userinfo值。總之一句,有completionHandler參數(shù)的必須要調(diào)用該參數(shù),否則,請(qǐng)求將無法繼續(xù)。

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

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