NSURLSession
是在NSURLConnection
以後出來的用來取代NSURLConnection
進行網絡請求的。NSURLSession
並不僅僅指這個類自己,它其實是指代 Foundation框架的URL加載系統中一些列相關的類和協議,它主要由NSURLSessionConfiguration
、NSURLSession
和NSURLSessionTask
這三個類及其子類以及相關的協議構成。web
其中NSURLSessionConfiguration
用於配置可用網絡、Cookie、安全性、緩存策略、自定義協議、啓動事件等選項,用來對NSURLSession
對象進行初始。NSURLSession
主要負責網絡的請求與響應。NSURLSessionTask
用於建立各類獲取數據、上傳、下載等任務並執行任務。數組
NSURLSessionConfiguration
對象用於對NSURLSession
進行初始化。NSURLSessionConfiguration
有3種初始化方式。緩存
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
複製代碼
這種方式建立的config
是一個標準的配置,具備共享NSHTTPCookieStorage
、共享NSURLCache
、共享NSURLCredentialStorage
。安全
NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
複製代碼
這種方式建立的config
不會對緩存、Cookie和證書進行持久性存儲。當這種方式建立的session
釋放時或者收到內存警告時或者程序退出時,其緩存的相關信息就會被清除。bash
NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"abc"];
複製代碼
這種方式建立的config
用於建立一個能夠後臺執行的session
,當咱們須要在程序掛起或退出的狀況下繼續進行上傳或下載任務,就能夠用這種方式來建立。這種方式建立config
時須要帶一個惟一標識(identifier
),這個標示不能爲nil或空字符串,當程序退出後從新啓動時能夠經過這個標示來恢復未完成的下載或上傳任務。服務器
@property (nullable, readonly, copy) NSString *identifier;
複製代碼
identifier
是隻讀的,只能經過backgroundSessionConfigurationWithIdentifier:
這個方法初始化時傳進來,這個標示不能爲nil或空字符串,當程序退出後從新啓動時能夠經過這個標示來恢復未完成的下載或上傳任務。cookie
@property NSURLRequestCachePolicy requestCachePolicy;
複製代碼
requestCachePolicy
是緩存策略,是一個枚舉類型,以下所示:網絡
typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
// 默認的緩存策略,若是緩存不存在,直接從服務端獲取,若是緩存存在,會根據response中的Cache-Control字段判斷下一步操做,如:Cache-Control字段爲must-revalidata,則詢問服務端該數據時否有更新,無更新的話直接返回給用戶緩存數據,若已更新,則請求服務端。
NSURLRequestUseProtocolCachePolicy = 0,
// 忽略本地緩存數據,直接請求服務端
NSURLRequestReloadIgnoringLocalCacheData = 1,
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,
// 忽略本地緩存,代理服務器以及其餘中介,直接請求源服務器
NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4,
// 有緩存就用它,無論其有效性(忽略Cache-Control字段),沒有就請求服務器
NSURLRequestReturnCacheDataElseLoad = 2,
// 只從本地緩存加載,本地緩存沒有就不做操做(無網絡時使用)
NSURLRequestReturnCacheDataDontLoad = 3,
// 緩存數據必須獲得服務端確認有效才使用
NSURLRequestReloadRevalidatingCacheData = 5,
};
複製代碼
@property NSTimeInterval timeoutIntervalForRequest;
複製代碼
用於設置請求超時時長,默認是60s。session
@property NSTimeInterval timeoutIntervalForResource;
複製代碼
用於設置資源超時時長,默認是7天,也就是說資源要在7天內到達。app
@property NSURLRequestNetworkServiceType networkServiceType;
複製代碼
指定網絡傳輸類型,通常就用默認的。
typedef NS_ENUM(NSUInteger, NSURLRequestNetworkServiceType)
{
// 默認值,普通網絡傳輸
NSURLNetworkServiceTypeDefault = 0,
// 網絡語音通訊傳輸,只能用於IP語音流
NSURLNetworkServiceTypeVoIP = 1,
// 影像傳輸
NSURLNetworkServiceTypeVideo = 2,
// 網絡後臺傳輸
NSURLNetworkServiceTypeBackground = 3,
// 語音傳輸
NSURLNetworkServiceTypeVoice = 4,
// 指定請求是針對響應性(時間敏感)數據的
NSURLNetworkServiceTypeResponsiveData = 6,
NSURLNetworkServiceTypeAVStreaming = 8 ,
NSURLNetworkServiceTypeResponsiveAV = 9,
NSURLNetworkServiceTypeCallSignaling = 11,
};
複製代碼
@property BOOL allowsCellularAccess;
複製代碼
指定是否使用蜂窩網絡,默認爲YES。好比在用戶看視頻時沒有開啓WiFi,就能夠提示用戶是否使用流量。
@property BOOL allowsExpensiveNetworkAccess;
複製代碼
這是iOS 13新增的一個屬性,按照字面理解就是是否容許使用昂貴的網絡,在鏈接蜂窩數據或我的熱點時生效,系統自動判斷。(默認是YES)。
@property BOOL allowsConstrainedNetworkAccess;
複製代碼
這也是iOS 13新增的一個屬性,按照字面理解就是是否容許使用受限制的網絡,在開啓低流量模式時使用,用戶能夠設置。(默認是YES)。
@property BOOL waitsForConnectivity;
複製代碼
這個屬性用於設置是否等待網絡鏈接可用時再執行網絡請求任務,默認是NO。好比我如今只鏈接了蜂窩網絡,可是APP用戶設置的不容許經過蜂窩網絡進行網絡請求,若是waitsForConnectivity
這個屬性爲YES,那麼發起請求時就不會立馬返回網絡鏈接失敗的error,而是會等待網絡可用時(好比鏈接上了WiFi)再執行網絡請求,這種狀況下設置的timeoutIntervalForRequest
是不生效的,而timeoutIntervalForResource
是有效的。
@property (getter=isDiscretionary) BOOL discretionary;
複製代碼
用於肯定是否能夠根據系統的判斷來調度後臺任務以得到最佳性能。
@property (nullable, copy) NSString *sharedContainerIdentifier;
複製代碼
若是應用擴展(什麼是應用擴展?)在後臺建立了NSURLSession
任務,那就必須設置一個共享容器,以確保應用擴展和載體應用實現數據共享,sharedContainerIdentifier
就是用來指定共享容器的標示,而後咱們就能夠經過該標示符獲取到共享容器。
@property BOOL sessionSendsLaunchEvents;
複製代碼
用於設置在傳輸完成時是否應該在後臺繼續或啓動應用程序。默認爲YES,而且只有經過+backgroundSessionConfigurationWithIdentifier:
建立NSURLSessionConfiguration
時纔有效。
@property (nullable, copy) NSDictionary *connectionProxyDictionary;
複製代碼
包含有關在此session
中使用的代理信息的字典。
@property SSLProtocol TLSMinimumSupportedProtocol;
複製代碼
請求支持的最低 TLS 版本,默認值是 kSSLProtocol3,即 SSL3.0。
請求支持的最高 TLS 版本,默認值是 kTLSProtocol12,即 TLS1.2。
@property SSLProtocol TLSMaximumSupportedProtocol;
複製代碼
@property BOOL HTTPShouldUsePipelining;
複製代碼
用於開啓 HTTP 流水線(HTTP pipelining),能夠顯着減小請求的加載時間,可是因爲沒有被服務器普遍支持,默認是 NO 的。
@property BOOL HTTPShouldSetCookies;
複製代碼
指定了請求是否應該使用 Session 存儲的 Cookie,即 HTTPCookieStorage 屬性的值。
@property NSHTTPCookieAcceptPolicy HTTPCookieAcceptPolicy;
typedef NS_ENUM(NSUInteger, NSHTTPCookieAcceptPolicy) {
NSHTTPCookieAcceptPolicyAlways, // 接受全部的cookies
NSHTTPCookieAcceptPolicyNever, // 拒絕全部的cookies
NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain // 只接受從主文檔中域的cookie
};
複製代碼
決定了什麼狀況下 Session 應該接受從服務器發出的 Cookie。
@property (nullable, copy) NSDictionary *HTTPAdditionalHeaders;
複製代碼
是一個字典,包含了須要額外添加到session
中的reques
請求頭(header),默認爲空。若是在HTTPAdditionalHeaders
額外添加的頭部字段與NSURLRequest
中重複了,則優先使用NSURLRequest
對象中的請求頭部字段。
NSURLSession
已經默認給NSURLRequest
添加一些請求頭部字段,包括Authorization
、Connection
、Host
、Proxy-Authenticate
、Proxy-Authorization
、WWW-Authenticate
。
HTTPAddtionalHeaders
能夠額外添加的請求頭部字段包括Accept
、Accept-Language
、User-Agent
等。
@property NSInteger HTTPMaximumConnectionsPerHost;
複製代碼
指定session
內能夠同時鏈接一個主機的最大鏈接數。
@property (nullable, retain) NSHTTPCookieStorage *HTTPCookieStorage;
複製代碼
存儲了session
所使用的cookie
。經過defaultSessionConfiguration
和backgroundSessionConfigurationWithIdentifier:
建立的config
會使用NSHTTPCookieStorage
的+ sharedHTTPCookieStorage
單例,要清除存儲的cookie,直接set爲nil便可。經過ephemeralSessionConfiguration
建立的config``cookie
僅僅儲存到內存,session失效時會自動清除。
@property (nullable, retain) NSURLCredentialStorage *URLCredentialStorage;
複製代碼
證書存儲。經過defaultSessionConfiguration
和backgroundSessionConfigurationWithIdentifier:
建立的config
會使用NSURLCredentialStorage
的+ sharedCredentialStorage
單例,要清除存儲的證書,直接set爲nil便可。經過ephemeralSessionConfiguration
建立的config
證書僅僅儲存到內存,session失效時會自動清除。
@property (nullable, retain) NSURLCache *URLCache;
複製代碼
緩存NSURLRequest的response。默認的configuration
,默認值的是sharedURLCache
,後臺的configuration
,默認值是nil。短暫的configuration
,cache存於內存,session失效,cache自動清除。
@property BOOL shouldUseExtendedBackgroundIdleMode;
複製代碼
爲建立的任何tcp套接字啓用擴展後臺空閒模式。 啓用此模式會要求系統保持打開狀態,並在進程移動到後臺時延遲迴收。
@property(copy) NSArray<Class> *protocolClasses;
複製代碼
用來配置特定某個session
所使用的自定義協議(該協議是 NSURLProtocol 的子類)的數組。
@property NSURLSessionMultipathServiceType multipathServiceType;
typedef NS_ENUM(NSInteger, NSURLSessionMultipathServiceType)
{
NSURLSessionMultipathServiceTypeNone = 0, // 不使用多路徑TCP服務(默認)
NSURLSessionMultipathServiceTypeHandover = 1, // 多路徑TCP服務,提供Wi-Fi和蜂窩之間的無縫切換,以保持鏈接。
NSURLSessionMultipathServiceTypeInteractive = 2, // 嘗試使用最低延遲接口的服務
NSURLSessionMultipathServiceTypeAggregate = 3 //聚合其餘多路徑選項容量的服務,旨在提升吞吐量和最小化延遲。
}
複製代碼
指定經過 Wi-Fi 和 蜂窩網絡傳輸數據的多路徑 TCP 的鏈接策略。
咱們可使用NSURLSession
的API來建立一個或多個session
對象,每一個session
對象均可以管理多個網絡請求任務。建立會話(session
)的方式有3種:
NSURLSession *session = [NSURLSession sharedSession];
複製代碼
經過這種方式獲取全局的NSURLSession
對象。
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
複製代碼
先建立一個NSURLSessionConfiguration
對象config
,而後根據config
來建立session
。
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config
delegate:self
delegateQueue:[NSOperationQueue new]];
複製代碼
這種方式一樣須要一個NSURLSessionConfiguration
對象,而且要遵循NSURLSessionDelegate
協議。
NSURLSessionTask
是一個抽象類,它包含3個子類:NSURLSessionDataTask
、NSURLSessionUploadTask
、NSURLSessionDownloadTask
。它們的繼承關係以下:
NSURLSessionTask
的數據返回方式主要有兩種,一種是回調(completionHandler
),另外一種是代理。不論是哪種task
,其建立都是基於NSURLSession
對象,建立task
後必定要調用[task resume]
來啓動任務。
NSURLSessionDataTask
繼承自NSURLSessionTask
,主要用於讀取服務端的簡單數據,好比JSON數據。建立NSURLSessionDataTask
有4種方式,分別是基於NSURL
和NSURLRequest
對象來建立,每種又分爲帶回調和不帶回調2種。
NSURL *url = [NSURL URLWithString:@"http://aaa.bbb/test/login"];
// 注意,請求對象內部默認已經包含了請求頭和請求方法(GET)
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];
// 第一種:基於NSURL建立不帶回調的task
NSURLSessionDataTask *task1 = [session dataTaskWithURL:url];
// 第二種:基於NSURLRequest建立不帶回調的task
NSURLSessionDataTask *task2 = [session dataTaskWithRequest:request];
// 第三種:基於NSURL建立帶回調的task
NSURLSessionDataTask *task3 = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
// 第四種:基於NSURLRequest建立帶回調的task
NSURLSessionDataTask *task4 = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
// 每一個task都要調用resume方法纔會執行task
[task1 resume];
複製代碼
NSURLSessionUploadTask
繼承自NSURLSessionDataTask
,主要用於 向服務器上傳文件類型的數據。有5種建立任務的方法。
// 第1、二種,經過文件路徑上傳(一種帶回調一種不帶回調),這種方式上傳不須要把文件內容所有加載到內存中
- (void)NSURLSessionUploadTask1{
NSURL *fileUrl = [NSURL fileURLWithPath:@"/user/file/abc.txt"];
NSURL *url = [NSURL URLWithString:@"http://aaa.bbb/test/upload"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"text/plain" forHTTPHeaderField:@"Content-Type"];
NSURLSession *session = [NSURLSession sharedSession];
// 不帶回調
NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromFile:fileUrl];
// 帶回調
NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromFile:fileUrl completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
[task resume];
}
複製代碼
// 第3、四種,上傳NSData(帶回調和不帶回調兩種),這種方式上傳文件時須要先將文件加載到內存中
- (void)NSURLSessionUploadTask2{
NSData *data = [NSData dataWithContentsOfFile:@"/user/file/abc.txt"];
NSURL *url = [NSURL URLWithString:@"http://aaa.bbb/test/upload"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)data.length] forHTTPHeaderField:@"Content-Length"];
[request setValue:@"text/plain" forHTTPHeaderField:@"Content-Type"];
NSURLSession *session = [NSURLSession sharedSession];
// 不帶回調
NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromData:data];
// 帶回調
NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromData:data completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
[task resume];
}
複製代碼
// 第五種,經過表單上傳,將要上傳的數據二進制寫入httpbody中,而後將其添加到請求頭中
- (void)NSURLSessionUploadTask3{
NSURL *url = [NSURL URLWithString:@"http://aaa.bbb/test/upload"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBodyStream = [NSInputStream inputStreamWithFileAtPath:@"/user/file/abc.txt"];
[request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)data.length] forHTTPHeaderField:@"Content-Length"];
[request setValue:@"text/plain" forHTTPHeaderField:@"Content-Type"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionUploadTask *task = [session uploadTaskWithStreamedRequest:request];
[task resume];
}
複製代碼
NSURLSessionDownloadTask
繼承自NSURLSessionTask
,主要用於文件下載。有6種建立下載任務的方式。須要注意的是文件下載保存的是一個臨時文件,下載完後要將其拷貝到本身想要存儲的目錄再刪除臨時文件。
- (void)NSURLSessionDownloadTaskTest{
NSString *urlStr = @"http://aaa.bbb/test/downloadFile.zip";
NSURL *url = [NSURL URLWithString:urlStr];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 不須要後臺下載的話就用其餘方式初始化config
NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"abcd"];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
// 第一種,經過一個NSURL對象來建立task(不帶回調)
NSURLSessionDownloadTask *task1 = [session downloadTaskWithURL:url];
// 第二種,經過一個NSURL對象來建立task(帶回調)
NSURLSessionDownloadTask *task2 = [session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
// 第三種,經過一個NSURLRequest對象來建立task(不帶回調)
NSURLSessionDownloadTask *task3 = [session downloadTaskWithRequest:request];
// 第四種,經過一個NSURLRequest對象來建立task(帶回調)
NSURLSessionDownloadTask *task4 = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
// 第五種,經過一個resumeData(保存在沙盒中的下載進度)數據來建立task(不帶回調)
NSString *resumePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"123.tmp"];
NSData *resumeData = [NSData dataWithContentsOfFile:resumePath];
NSURLSessionDownloadTask *task5 = [session downloadTaskWithResumeData:resumeData];
// 第六種,經過一個resumeData數據來建立task(帶回調)
NSURLSessionDownloadTask *task6 = [session downloadTaskWithResumeData:resumeData completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
// 啓動任務
[task1 resume];
}
複製代碼
當暫停下載時會產生一個記錄下載進度的數據resumeData
經過回調傳過來,咱們要將這個數據保存在沙盒中,以便繼續下載時能夠經過這個數據來建立下載任務(斷點續傳)。
// 暫停下載
- (void)pauseDownload {
[self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
// 記錄已下載的數據
// 把下載進度數據保存到沙盒中
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"123.tmp"];
[self.resumData writeToFile:path atomically:YES];
}];
}
複製代碼
相關代理主要有四個:NSURLSessionDelegate
、NSURLSessionTaskDelegate
、NSURLSessionDataDelegate
、NSURLSessionDownloadDelegate
。它們的繼承關係以下:
NSURLSessionDelegate
用於處理session
級別的事件,好比session
的生命週期和服務端請求驗證客戶端的身份或證書。
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error;
複製代碼
當session
失效時會調用這個代理方法,有如下兩種方法使session
失效。
- (void)finishTasksAndInvalidate;
:session
將等到全部task
結束或失敗後才調用這個委託方法。- (void)invalidateAndCancel;
:session
將直接取消全部正在執行的task
,當即調用此委託方法。- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session;
複製代碼
若是是經過backgroundSessionConfigurationWithIdentifier:
方式建立的configuration
,再經過這個configuration
建立的session
用於管理能夠後臺執行的上傳或下載任務,當後臺傳輸完成時就會調用上面這個代理方法。
當後臺傳輸完成時,若是此時APP處於未啓動狀態,那麼APP會自動在後臺從新啓動,啓動後會調用UIApplicationDelegate
中下面這個代理方法,裏面包含一個會話標示符(identifier
)和completionHandler
,咱們首先要將completionHandler
保存起來,而後根據identifier
從新生成configuration
,而後經過這個configuration
建立的session
將從新關聯對應的後臺任務。
// UIApplicationDelegate中的方法
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler;
複製代碼
當服務器請求客戶端證書或請求驗證NTLM身份驗證時,或者使用SSL或TLS鏈接服務器時都會調用下面這個代理方法。
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler{
/*
challenge是一個封裝了服務端發過來的驗證請求的對象,經過下面這個方法能夠獲取驗證方式,驗證方式有以下幾種狀況:
NSURLAuthenticationMethodClientCertificate 表示要求驗證客戶端的證書
NSURLAuthenticationMethodNegotiate 使用Kerberos或NTLM身份驗證
NSURLAuthenticationMethodNTLM 使用NTLM身份驗證
NSURLAuthenticationMethodServerTrust 驗證服務端提供的證書
*/
NSString *authenticationMethod = [challenge.protectionSpace authenticationMethod];
/*
completionHandler回調要傳2個參數:
第一個參數是一個枚舉:
typedef NS_ENUM(NSInteger, NSURLSessionAuthChallengeDisposition) {
NSURLSessionAuthChallengeUseCredential = 0, // 指明經過另外一個參數 credential 提供證書
NSURLSessionAuthChallengePerformDefaultHandling = 1, // 至關於未執行代理方法,使用默認的處理方式,不使用參數 credential
NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, // 取消整個請求,提供的憑證參數被忽略
NSURLSessionAuthChallengeRejectProtectionSpace = 3, // 拒絕該 protectionSpace 的驗證,不使用參數 credential
}
第二個參數:
第二個參數爲NSURLCredential類型,它是一種身份驗證憑證,包含特定於憑證類型的信息和用於使用的持久存儲類型。
當第一個參數爲NSURLSessionAuthChallengeUseCredential時,第二個參數必須傳身份驗證的憑據,不然就傳nil;
經過NSURLCredential能夠建立3種類型的credential:
1.當authenticationMethod的值爲NSURLAuthenticationMethodHTTPBasic 或 NSURLAuthenticationMethodHTTPDigest時,調用如下方法來建立:
- (instancetype)initWithUser:(NSString *)user password:(NSString *)password persistence:(NSURLCredentialPersistence)persistence;
+ (NSURLCredential *)credentialWithUser:(NSString *)user password:(NSString *)password persistence:(NSURLCredentialPersistence)persistence;
2.當authenticationMethod的值爲NSURLAuthenticationMethodClientCertificate時,調用如下方法來建立:
- (instancetype)initWithIdentity:(SecIdentityRef)identity certificates:(nullable NSArray *)certArray persistence:(NSURLCredentialPersistence)persistence;
+ (NSURLCredential *)credentialWithIdentity:(SecIdentityRef)identity certificates:(nullable NSArray *)certArray persistence:(NSURLCredentialPersistence)persistence;
3.當authenticationMethod的值爲NSURLAuthenticationMethodServerTrust時,調用如下方法來建立:
- (instancetype)initWithTrust:(SecTrustRef)trust;
+ (NSURLCredential *)credentialForTrust:(SecTrustRef)trust;
*/
}
複製代碼
若是上面這個代理方法沒有實現的話就會調用NSURLSessionTaskDelegate
的下面這個方法:
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{
/*
這裏的authenticationMethod有如下幾種可能
NSURLAuthenticationMethodDefault 默認的驗證
NSURLAuthenticationMethodHTMLForm 不會用於 URL Loading System,在經過 web 表單驗證時可能用到
NSURLAuthenticationMethodHTTPBasic 基本的 HTTP 驗證,經過 NSURLCredential 對象提供用戶名和密碼,至關於 Default 默認的驗證
NSURLAuthenticationMethodHTTPDigest 相似於基本的 HTTP 驗證,摘要會自動生成,一樣經過 NSURLCredential 對象提供用戶名和密碼
*/
NSString *authenticationMethod = [challenge.protectionSpace authenticationMethod];
}
複製代碼
NSURLSessionTaskDelegate
用於處理task
級別的事件。
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error;
複製代碼
當任務完成時會回到這個方法。要注意的是這裏的error
只有客戶端的錯誤,好比沒法解析主機名或鏈接到主機。服務端的錯誤是不會經過這個error
傳過來的。
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest *))completionHandler;
複製代碼
當服務器請求HTTP重定向時會調用這個方法。注意這個方法只適用於defaultSessionConfiguration
和ephemeralSessionConfiguration
的session
生成的session
,backgroundSessionConfigurationWithIdentifier:
生成的session
會自動重定向,而不會走這個方法。
response
是服務器對原始請求的響應request
是新的NSURLRequest
completionHandler
回調能夠傳一個重定向的NSURLRequest
對象,也能夠傳nil,傳nil的話就不進行重定向。- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend;
複製代碼
執行上傳任務時,會按期調用這個代理方法來告知上傳進度。
bytesSent
是從上次調用這個方法開始到此次調用這個方法期間發送的字節數。totalBytesSent
是已經發送的總的字節數。totalBytesExpectedToSend
是要上傳的數據的總長度。- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler;
複製代碼
當咱們經過uploadTaskWithStreamedRequest:
這個方法來建立任務時,必需要實現這個代理方法,當調用這個方法時,須要經過completionHandler
回調傳入NSInputStream
對象。由於上傳可能失敗,當失敗時就會調用這個代理方法,就須要在這個方法裏面從新提供請求體流。
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler;
複製代碼
這個代理方法用於處理task
級別的身份驗證,當session
級別的身份認證代理函數沒有實現的話就會走這個代理,具體請求前面已經介紹過了,這裏再也不贅述。
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
willBeginDelayedRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLSessionDelayedRequestDisposition disposition, NSURLRequest *newRequest))completionHandler;
// disposition的枚舉類型
typedef NS_ENUM(NSInteger, NSURLSessionDelayedRequestDisposition) {
NSURLSessionDelayedRequestContinueLoading = 0, // 繼續執行原始請求
NSURLSessionDelayedRequestUseNewRequest = 1, // 使用新請求執行下載
NSURLSessionDelayedRequestCancel = 2, // 取消該任務
}
複製代碼
當一個延遲啓動的任務(好比設置了earliestBeginDate
這個屬性)準備啓動時就會調用這個代理方法。只有在等待網絡加載而且須要被新的請求替換時才須要實現這個委託方法。
經過completionHandler
回調告訴task
如何處理。當disposition
爲NSURLSessionDelayedRequestUseNewRequest
時須要同時傳一個新的NSURLRequest
對象。
- (void)URLSession:(NSURLSession *)session
taskIsWaitingForConnectivity:(NSURLSessionTask *)task;
複製代碼
當NSURLSessionConfiguration
的waitsForConnectivity
屬性設置爲YES而且沒法得到足夠的鏈接性時就會調用這個代理方法。好比當前用戶只連了蜂窩網絡,但用戶又設置了只能在WiFi鏈接時才能看視頻,當用戶播放視頻時就會調用這個代理方法,那咱們就能夠在這個代理方法裏面更新UI提示用戶鏈接WiFi。要注意每一個任務最多調用此方法一次,而且只在鏈接最初不可用時調用。
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics;
複製代碼
當任務執行完成後,能夠經過這個方法知道任務的執行狀況,好比任務執行的時長、重定向次數等信息放在NSURLSessionTaskMetrics
對象裏面。
NSURLSessionDataDelegate
繼承自NSURLSessionTaskDelegate
,主要用來處理dataTask
數據(好比接收到響應,接收到數據,是否緩存數據等)。
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;
// disposition的枚舉類型
typedef NS_ENUM(NSInteger, NSURLSessionResponseDisposition) {
NSURLSessionResponseCancel = 0, // 該task會被取消
NSURLSessionResponseAllow = 1, // 該task正常進行
NSURLSessionResponseBecomeDownload = 2, // 轉成一個downloadTask
NSURLSessionResponseBecomeStream // 轉成一個StreamTask
}
複製代碼
當DataTask
收到響應時,會調用這個代理方法。咱們須要經過completionHandler
回調指明任務後續執行方式。
disposition
爲NSURLSessionResponseBecomeDownload
時,是將task
轉換爲download task
,同時會調用URLSession:dataTask:didBecomeDownloadTask:
這個代理方法。disposition
爲NSURLSessionResponseBecomeStream
時,是將task
轉換爲StreamTask
,同時會調用URLSession:dataTask:didBecomeStreamTask:
這個代理方法。當咱們的request
的content-type
支持multipart/x-mixed-replace
時,服務器會將數據分片傳回來,並且每次傳回來的數據會覆蓋以前的數據。每次返回新的數據時,都會調用這個方法個,咱們應該在這個函數中合理地處理先前的數據,不然會被新數據覆蓋。若是咱們沒有提供該方法的實現,那麼session將會繼續任務,也就是說會覆蓋以前的數據。
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask;
複製代碼
上面已經介紹了何時會調用這個代理方法。
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask;
複製代碼
上面已經介紹了何時會調用這個代理方法。
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data;
複製代碼
當咱們收到數據時就會調用這個代理方法,這個方法個會被屢次調用,咱們須要將每次收到的數據拼接起來獲得完整的數據。
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler;
複製代碼
當task
接收到全部指望的數據後,session
會調用此代理方法。若是沒有實現該方法,那麼就會使用建立session
時使用的configuration
對象的緩存策略。
NSURLSessionDownloadDelegate
繼承自NSURLSessionTaskDelegate
,主要用來處理下載任務。
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location;
複製代碼
當下載任務完成後會調用這個代理方法,這個方法是必現實現的。location
是下載文件保存的路徑,要注意的是咱們必如今這個方法裏面將下載的文件保存到咱們想要保存的目錄去,由於這裏返回的是一個臨時路徑,這個方法結束後這個路徑下的文件就會被刪除。另外,若是讀取文件內容的話,須要在子線程執行,不然可能會形成頁面卡死。
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes;
複製代碼
當下載被取消或者下載失敗後從新恢復下載時會調用這個代理方法。注意fileOffset
這個參數,若是文件緩存策略或者文件最後更新日期阻止重用已經下載的文件內容,那麼該值爲0。不然,該值表示當前已經下載data的偏移量,那就會從這個偏移量開始下載,已經下載的不會從新下載。
恢復下載時經過downloadTaskWithResumeData:
這個方法個來建立任務,那這個resumeData
從哪裏獲取呢?前面講過一種狀況,就是當用戶手動取消下載時能夠將返回的resumeData
存入沙盒,恢復下載時再從沙盒去獲取。
下面咱們來介紹一下另外一種狀況,當下載失敗時會調用-URLSession: task: didCompleteWithError:
這個代理方法,這個方法的error
信息裏面是攜帶了resumeData
的,能夠從error
的UserInfo
字典中經過NSURLSessionDownloadTaskResumeData
這個鍵來獲取resumeData
。
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
複製代碼
下載任務執行過程當中週期性調用這個代理方法來通知下載進度。
bytesWritten
表示從上次調用這個方法開始到此次調用這個方法個期間接收到的數據字節數。totalBytesWritten
表示已經接收到的總字節數。totalBytesExpectedToWrite
表示要下載的數據總長度。