AFNetWorking源碼之NSURLSession系列概述

1 基本說明

記得我剛做iOS的時候,那時候還是ASI和AFN共存,甚至ASI使用比例還多點,一轉(zhuǎn)眼幾年過去,ASI基本已經(jīng)消失了,AFN基本成了iOS項目的標(biāo)配。我雖然以前也有看過AFN2.x的源碼,但是對于AFN3.x的源碼一直沒有自己閱讀。接下來我會對AFN3.x學(xué)習(xí)并且寫博客記錄。得益于NSURLSession的強(qiáng)大功能,ANF3.0放棄了NSURLConnection這一部分,讓代碼簡化了很多,但是功能卻更加豐富。我覺得在學(xué)習(xí)AFN之前,有必要仔細(xì)了解NSURLSessionhttps相關(guān),不然會有很多地方迷惑不解,具體可以看我的git倉庫iOSSourceCodeStudy
。同時我強(qiáng)烈推薦瀏覽一下NSURLSession.h這個文件。

2 相互關(guān)系

我們首先來看一下一個簡單的NSURLSession請求代碼:

    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
    
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:bigPic]];
    
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
    [dataTask resume];

從上面我們發(fā)現(xiàn),我們要發(fā)送一個網(wǎng)絡(luò)請求,需要新建一個NSURLSession,新建一個NSURLSession又需要一個NSURLSessionConfiguration,并且還需要一些代理方法。同時我們需要一個NSURLSessionDataTask。所以說,我們的NSRULSession
網(wǎng)絡(luò)請求系統(tǒng)包括一個session、一個configuration、一個Task已經(jīng)Task附帶的delegate。

  • 一個NSURLSession,總共只有一個類,也是最核心的類,他有一個對應(yīng)的代理NSURLSessionDelegate。
  • 一個NSURLSessionConfiguration,總共有三種模式。
  • 一個NSURLSessionTask。NSURLSessionTask是抽閑類,對應(yīng)的代理NSURLSessionTaskDelegate。我們具體使用的時候,會使用他的三種子類,而且每個子類都有對應(yīng)的delegate。

3 一個NSURLSession

首先我們看一下NSRULSession.h里面關(guān)于NSURLSession的部分。我們把它分為初始化部分、屬性部分、dataTask部分、uploadTask部分、downloadTask部分。也就是說其他很多類都是圍繞著下面這幾個api衍生的。后面我們會每個部分分析。

//初始化部分
@property (class, readonly, strong) NSURLSession *sharedSession;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;

//屬性部分
@property (readonly, retain) NSOperationQueue *delegateQueue;
@property (nullable, readonly, retain) id <NSURLSessionDelegate> delegate;
@property (readonly, copy) NSURLSessionConfiguration *configuration;

//dataTask部分
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;

//uploadTask部分
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData;
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request;

//downloadTask部分
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request;
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url;
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;

3.1 Block的NSURLSession的api

我們都知道,NSRULConnection除了一套使用代理的API,還有一套對應(yīng)的使用Block的api。NSURLSession也不列外。使用這一套api就不用實現(xiàn)代理方法。和delegate一樣,Block也有dataTask系列、downloadTask系列、uploadTask系列。具體看下面:

//dataTask系列
- (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{
    
}
//unloadTast系列
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{
    
}
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(nullable NSData *)bodyData completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{
    
}
//downloadTask系列
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{
    
}
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{
    
}
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData completionHandler:(void (^)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler{
    
}

3.2 Block的NSURLSession使用

用dataTask下載一張圖片,然后用imageView顯示。

-(IBAction)requestBlockTaskTest:(id)sender{
    [self clear];
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:bigPic]];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        UIImage *image = [[UIImage alloc]initWithData:data];
        self.imageView.image = image;
    }];
    [dataTask resume];
}

4 一個NSURLSessionConfiguration

首先看一下NSURLSessionConfiguration部分。從這個名字,我們可以預(yù)感到這個是與session的配置相關(guān)的,的確也是這樣??偣灿腥N類型的configuratin,另外還有很多屬性,比如配置緩存策略的requestCachePolicy,請求超時的timeoutIntervalForRequest,添加額外請求頭的HTTPAdditionalHeaders,其他還有很多屬性這里就不一一說了,具體看源碼:

//默認(rèn)的配置會將緩存存儲在磁盤上
@property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration;
//第二種瞬時會話模式不會創(chuàng)建持久性存儲的緩存.
@property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration;
//第三種后臺會話模式允許程序在后臺進(jìn)行上傳下載工作
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier;
//各種屬性
@property NSURLRequestCachePolicy requestCachePolicy;
@property NSTimeInterval timeoutIntervalForRequest;
@property (nullable, copy) NSDictionary *HTTPAdditionalHeaders;

5 一個NSURLSessionTask

從上面NSURLSession初始化一個請求的時候,我們發(fā)現(xiàn)NSURLSessionTask并不能直接使用,只能使用他的子類。具體如下:

  • NSURLSessionTask抽象類。有對應(yīng)的代理NSURLSessionTaskDelegate,而且這個代理繼承了NSURLSessionDelegate代理。
  • NSURLSessionDataTaskNSURLSessionTask的子類。有對應(yīng)的代理NSURLSessionTaskDelegate,而且這個代理繼承了NSURLSessionTaskDelegate代理。我們一般網(wǎng)絡(luò)請求,就用這個類。
  • NSURLSessionDownloadTaskNSURLSessionTask的子類。有對應(yīng)的代理NSURLSessionDownloadDelegate,而且這個代理繼承了NSURLSessionTaskDelegate代理。這個主要用于下載大文件等。
  • NSURLSessionUploadTaskNSURLSessionDataTask的子類。有對應(yīng)的代理及時父類代理NSURLSessionDownloadDelegate。這個主要用于處理上傳請求如上傳圖片。

從上面我們發(fā)現(xiàn)Task和delegate有一套對應(yīng)的繼承關(guān)系:

  • NSURLSessionTask (抽象類,NSURLSessionTaskDelegate)

    • NSURLSessionDataTask (NSURLSessionDataDelegate)
      • NSURLSessionUploadTask (NSURLSessionDataDelegate)
    • NSURLSessionDownloadTask (NSURLSessionDownloadDelegate)
  • NSURLSessionDelegate

    • NSURLSessionTaskDelegate
      • NSURLSessionDataDelegate
      • NSURLSessionDownloadDelegate

從繼承關(guān)系上,我們就可以理解在初始化的時候,只通過設(shè)置NSURLSession對象的delegate就可以了。因為根據(jù)不同的task,其實就是設(shè)置了不同的delegate。這個設(shè)計避免了多次設(shè)置delegate的情況,同時也根據(jù)不同的task實現(xiàn)不同的delegate方法。真是一個很絕妙的設(shè)計。

6 代理說明

6.1 NSURLSessionDelegate

接下來我們看看NSURLSession的delegate對象NSURLSessionDelegate的方法,當(dāng)一個session遇到錯誤、或者需要認(rèn)證、應(yīng)用進(jìn)入后臺都會調(diào)用下面的代理方法:

//當(dāng)一個session遇到系統(tǒng)錯誤或者未檢測到的錯誤的時候,就會調(diào)用這個方法。
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error{

}
//當(dāng)請求需要認(rèn)證、或者h(yuǎn)ttps證書認(rèn)證的時候,我們就需要在這個方法里面處理。
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{
    
}
//如果應(yīng)用進(jìn)入后臺、這個方法會被調(diào)用。我們在這里可以對session發(fā)起的請求做各種操作比如請求完成的回調(diào)等。
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {

}

6.2 NSURLSessionTaskDelegate

/*
 當(dāng)請求重定向的時候調(diào)用這個方法。我們必須設(shè)置一個新的`NSURLRequest`對象傳入completionHandler來重定向新的請求,但是當(dāng)`session`是background模式的時候,這個方法不會被調(diào)用。
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
        newRequest:(NSURLRequest *)request
 completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler{

}
/*
 當(dāng)請求需要認(rèn)證的時候調(diào)用這個方法。如果沒有實現(xiàn)這個代理,那么請求認(rèn)證這個過程不會被調(diào)用。
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{

}
/*
    如果請求需要一個新的請求體時,這個方法就會被調(diào)用。比如認(rèn)證失敗的時候,我們可以通過這個機(jī)會從新認(rèn)證。
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
 needNewBodyStream:(void (^)(NSInputStream * _Nullable bodyStream))completionHandler{

}
/*
 當(dāng)我們上傳數(shù)據(jù)的時候,我們可以通過這個代理方法獲取上傳進(jìn)度。
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
   didSendBodyData:(int64_t)bytesSent
    totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{

}
/*
 當(dāng)task的統(tǒng)計信息收集好了以后,調(diào)用這個方法。
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics {

}
/*
 當(dāng)一個task出錯的時候,會調(diào)用這個方法。如果error是nil,也會調(diào)用這個方法,表示task完成。
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error{
    NSLog(@"數(shù)據(jù)返回以后,不管有錯沒錯都回調(diào)用,如果沒錯,error及時nil");
}

6.3 NSURLSessionDataDelegate

/*
 當(dāng)一個task接收到返回信息。當(dāng)所有信息都接收完畢以后,completionHandler會被調(diào)用。我們可以在這里取消一個網(wǎng)絡(luò)請求或者把一個datatask轉(zhuǎn)換為downloadtask。如果沒有實現(xiàn)這個代理方法,我們也可以通過task的response屬性獲取到對應(yīng)的數(shù)據(jù)。background模式的uploadtask不會調(diào)用這個方法。
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler{

}
/*
 當(dāng)一個datatask轉(zhuǎn)換為一個downloadtask以后會調(diào)用。
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask{
    // 允許處理服務(wù)器的響應(yīng),才會繼續(xù)接收服務(wù)器返回的數(shù)據(jù)
    completionHandler(NSURLSessionResponseAllow);
}
/*
 暫時忽略,這個是和數(shù)據(jù)流相關(guān)的。不管了
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask{

}
/*
 當(dāng)data可以使用的時候,調(diào)用這個方法。我們可以在這里獲取data。
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data{

}
/*
 允許我們在這里調(diào)用completionHandler緩存data,或者傳入nil來禁止緩存
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
 willCacheResponse:(NSCachedURLResponse *)proposedResponse
 completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler{

}

6.4 NSURLSessionDownloadDelegate

/*
    當(dāng)一個下載task任務(wù)完成以后,這個方法會被調(diào)用。我們可以在這里移動或者復(fù)制download的數(shù)據(jù)
 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location{

}
/*
 獲取下載進(jìn)度
 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{

}
/*
 重啟一個下載任務(wù)(比如下載一半后停止然后過一點時間繼續(xù))。如果下載出錯,`NSURLSessionDownloadTaskResumeData`里面包含重新開始下載的數(shù)據(jù)。
 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
 didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{

}

7 NSURLSession的綜合使用案列

分別用三種不同方式下載一張圖片然后在imageView上顯示。

#import "ViewController.h"

static NSString *const bigPic = @"http://i1.piimg.com/4851/d1498fea89ae3bc1.png";
static NSString *const smallPic = @"http://i1.piimg.com/4851/97aef4680d359905.png";

@interface ViewController ()<NSURLSessionDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property(nonatomic,strong)NSMutableData *data;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Do any additional setup after loading the view, typically from a nib.
}

- (IBAction)requestDataTest:(id)sender {
     [self clear];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:bigPic]];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
    [dataTask resume];
}


- (IBAction)requestDownloadTest:(id)sender {
     [self clear];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:bigPic]];
    NSURLSessionDownloadTask *dataTask = [session downloadTaskWithRequest:request];
    [dataTask resume];
}

-(IBAction)requestBlockTaskTest:(id)sender{
    [self clear];
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:bigPic]];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        UIImage *image = [[UIImage alloc]initWithData:data];
        self.imageView.image = image;
    }];
    [dataTask resume];
}

-(void)clear{
    self.imageView.image = nil;
}

//==============================NSURLSessionDelegate========================
#pragma NSURLSessionDelegate
//當(dāng)一個session遇到系統(tǒng)錯誤或者未檢測到的錯誤的時候,就會調(diào)用這個方法。
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error{

}
//當(dāng)請求需要認(rèn)證、或者h(yuǎn)ttps證書認(rèn)證的時候,我們就需要在這個方法里面處理。
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{
    
}
//如果應(yīng)用進(jìn)入后臺、這個方法會被調(diào)用。我們在這里可以對session發(fā)起的請求做各種操作比如請求完成的回調(diào)等。
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {

}

//==================================NSURLSessionTaskDelegate====================
#pragma NSURLSessionTaskDelegate
/*
 當(dāng)請求重定向的時候調(diào)用這個方法。我們必須設(shè)置一個新的`NSURLRequest`對象傳入completionHandler來重定向新的請求,但是當(dāng)`session`是background模式的時候,這個方法不會被調(diào)用。
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
        newRequest:(NSURLRequest *)request
 completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler{

}
/*
 當(dāng)請求需要認(rèn)證的時候調(diào)用這個方法。如果沒有實現(xiàn)這個代理,那么請求認(rèn)證這個過程不會被調(diào)用。
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{

}
/*
    如果請求需要一個新的請求體時,這個方法就會被調(diào)用。比如認(rèn)證失敗的時候,我們可以通過這個機(jī)會從新認(rèn)證。
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
 needNewBodyStream:(void (^)(NSInputStream * _Nullable bodyStream))completionHandler{

}
/*
 當(dāng)我們上傳數(shù)據(jù)的時候,我們可以通過這個代理方法獲取上傳進(jìn)度。
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
   didSendBodyData:(int64_t)bytesSent
    totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
    NSLog(@"");
}
/*
 當(dāng)task的統(tǒng)計信息收集好了以后,調(diào)用這個方法。
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics {

}
/*
 當(dāng)一個task出錯的時候,會調(diào)用這個方法。如果error是nil,也會調(diào)用這個方法,表示task完成。
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error{
    NSLog(@"數(shù)據(jù)返回以后,不管有錯沒錯都回調(diào)用,如果沒錯,error及時nil");
    if (self.data) {
        self.imageView.image = [UIImage imageWithData:self.data];
        self.data = nil;
    }
}

//==================================NSURLSessionDataDelegate=====================================
#pragma NSURLSessionDataDelegate
/*
 當(dāng)一個task接收到返回信息。當(dāng)所有信息都接收完畢以后,completionHandler會被調(diào)用。我們可以在這里取消一個網(wǎng)絡(luò)請求或者把一個datatask轉(zhuǎn)換為downloadtask。如果沒有實現(xiàn)這個代理方法,我們也可以通過task的response屬性獲取到對應(yīng)的數(shù)據(jù)。background模式的uploadtask不會調(diào)用這個方法。
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler{
    self.data = nil;
    self.data = [NSMutableData data];
    // 允許處理服務(wù)器的響應(yīng),才會繼續(xù)接收服務(wù)器返回的數(shù)據(jù)
    completionHandler(NSURLSessionResponseAllow);
}
/*
 當(dāng)一個datatask轉(zhuǎn)換為一個downloadtask以后會調(diào)用。
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask{
    
}
/*
 暫時忽略,這個是和數(shù)據(jù)流相關(guān)的。不管了
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask{

}
/*
 當(dāng)data可以使用的時候,調(diào)用這個方法。我們可以在這里獲取data。
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data{
    [self.data appendData:data];
    NSLog(@"具體數(shù)據(jù)在URLSession:(NSURLSession *)session task:(NSURLSessionTask *)taskdidCompleteWithError:(nullable NSError *)error處理");
}
/*
 允許我們在這里調(diào)用completionHandler緩存data,或者傳入nil來禁止緩存
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
 willCacheResponse:(NSCachedURLResponse *)proposedResponse
 completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler{

}
//==================================NSURLSessionDownloadTask=================================
#pragma NSURLSessionDownloadTask
/*
    當(dāng)一個下載task任務(wù)完成以后,這個方法會被調(diào)用。我們可以在這里移動或者復(fù)制download的數(shù)據(jù)
 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location{
    NSString *path = location.absoluteString;
    UIImage *image = [[UIImage alloc]initWithData:[NSData dataWithContentsOfURL:location]];
    self.imageView.image = image;
    NSLog(@"數(shù)據(jù)下載完成以后,會保存在一個location的地方。%@",location);
}
/*
 獲取下載進(jìn)度
 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    NSLog(@"總得數(shù)據(jù)大小%lld----",bytesWritten);
}
/*
 重啟一個下載任務(wù)(比如下載一半后停止然后過一點時間繼續(xù))。如果下載出錯,`NSURLSessionDownloadTaskResumeData`里面包含重新開始下載的數(shù)據(jù)。
 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
 didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{

}
@end

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

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

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