版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2018.02.28 |
前言
我們做APP發起網絡請求,都離不開一個非常有用的框架AFNetworking,可以說這個框架的知名度已經超過了蘋果的底層網絡請求部分,很多人可能不知道蘋果底層是如何發起網絡請求的,但是一定知道
AFNetworking
,接下來幾篇我們就一起詳細的解析一下這個框架。感興趣的可以看上面寫的幾篇。
1. AFNetworking源碼探究(一) —— 基本介紹
2. AFNetworking源碼探究(二) —— GET請求實現之NSURLSessionDataTask實例化(一)
3. AFNetworking源碼探究(三) —— GET請求實現之任務進度設置和通知監聽(一)
4. AFNetworking源碼探究(四) —— GET請求實現之代理轉發思想(一)
5. AFNetworking源碼探究(五) —— AFURLSessionManager中NSURLSessionDelegate詳細解析(一)
6. AFNetworking源碼探究(六) —— AFURLSessionManager中NSURLSessionTaskDelegate詳細解析(一)
回顧
上一篇主要介紹了NSURLSessionTaskDelegate
中五個代理方法的實現及其使用場景和注意事項。這一篇主要介紹NSURLSessionDataDelegate
幾個代理方法。
1. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;
首先看一下蘋果該方法的API
/* The task has received a response and no further messages will be
* received until the completion block is called. The disposition
* allows you to cancel a request or to turn a data task into a
* download task. This delegate message is optional - if you do not
* implement it, you can get the response as a property of the task.
*
* This method will not be called for background upload tasks (which cannot be converted to download tasks).
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;
看一下AFN中該方法的實現
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
if (self.dataTaskDidReceiveResponse) {
disposition = self.dataTaskDidReceiveResponse(session, dataTask, response);
}
if (completionHandler) {
completionHandler(disposition);
}
}
這里,NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
表示默認為繼續進行。
-
completionHandler
這個block,通過傳入一個類型為NSURLSessionResponseDisposition
的變量來決定該傳輸任務接下來該做什么:-
NSURLSessionResponseAllow
該task正常進行 -
NSURLSessionResponseCancel
該task會被取消 -
NSURLSessionResponseBecomeDownload
會調用URLSession:dataTask:didBecomeDownloadTask:
方法來新建一個download task
以代替當前的data task
-
NSURLSessionResponseBecomeStream
轉成一個StreamTask
-
當你把添加
content-type
的類型為multipart/x-mixed-replace
那么服務器的數據會分片的傳回來。然后這個方法是每次接受到對應片響應的時候會調被調用。你應該在這個函數中合理地處理先前的數據,否則會被新數據覆蓋。
2. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask;
首先看一下蘋果該方法的API
/* Notification that a data task has become a download task. No
* future messages will be sent to the data task.
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask;
看一下AFN中該方法的實現
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
if (delegate) {
[self removeDelegateForTask:dataTask];
[self setDelegate:delegate forTask:downloadTask];
}
if (self.dataTaskDidBecomeDownloadTask) {
self.dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask);
}
}
當代理1方法中的disposition = NSURLSessionResponseBecomeDownload
的時候,就會調用這個方法。
這個代理方法是被上面的代理方法觸發的,作用就是新建一個downloadTask
,替換掉當前的dataTask
。所以我們在這里做了AF自定義代理的重新綁定操作[self setDelegate:delegate forTask:downloadTask];
。
3. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
首先看一下蘋果該方法的API
/* Sent when data is available for the delegate to consume. It is
* assumed that the delegate will retain and not copy the data. As
* the data may be discontiguous, you should use
* [NSData enumerateByteRangesUsingBlock:] to access it.
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data;
看一下AFN中該方法的實現
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
[delegate URLSession:session dataTask:dataTask didReceiveData:data];
if (self.dataTaskDidReceiveData) {
self.dataTaskDidReceiveData(session, dataTask, data);
}
}
- 獲取到數據就會調用,會被反復調用,請求到的數據就在這被拼裝完整。
- 這個方法和上面
didCompleteWithError
算是NSURLSession
的代理中最重要的兩個方法。 - 我們轉發了這個方法到AF的代理中去,所以數據的拼接都是在AF的代理中進行的。這也是情理中的,畢竟每個響應數據都是對應各個task,各個AF代理的。在
AFURLSessionManager
都只是做一些公共的處理。
4. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler;
首先看一下蘋果該方法的API
/* Invoke the completion routine with a valid NSCachedURLResponse to
* allow the resulting data to be cached, or pass nil to prevent
* caching. Note that there is no guarantee that caching will be
* attempted for a given resource, and you should not rely on this
* message to receive the resource data.
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler;
看一下AFN中該方法的實現
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
{
NSCachedURLResponse *cachedResponse = proposedResponse;
if (self.dataTaskWillCacheResponse) {
cachedResponse = self.dataTaskWillCacheResponse(session, dataTask, proposedResponse);
}
if (completionHandler) {
completionHandler(cachedResponse);
}
}
- 該方法的作用就是詢問data task或上傳任務(upload task)是否緩存response。
- 當task接收到所有期望的數據后,session會調用此代理方法。
- 當task接收到所有期望的數據后,session會調用此代理方法。如果你沒有實現該方法,那么就會使用創建session時使用的configuration對象決定緩存策略。這個代理方法最初的目的是為了阻止緩存特定的URLs或者修改
NSCacheURLResponse
對象相關的userInfo
字典。 - 該方法只會當
request
決定緩存response
時候調用。作為準則,responses只會當以下條件都成立的時候返回緩存:- 該request是HTTP或HTTPS URL的請求(或者你自定義的網絡協議,并且確保該協議支持緩存)
- 確保request請求是成功的(返回的status code為200-299)
- 返回的response是來自服務器端的,而非緩存中本身就有的
- 提供的
NSURLRequest
對象的緩存策略要允許進行緩存 - 服務器返回的response中與緩存相關的header要允許緩存
- 該response的大小不能比提供的緩存空間大太多(比如你提供了一個磁盤緩存,那么response大小一定不能比磁盤緩存空間還要大5%)
后記
本篇主要介紹了NSURLSessionDataDelegate中四個代理方法的實現及其使用場景和注意事項。